ManagementSystem/FRONTEND/src/pages/Profile/components/FileUploadForm.tsx

252 lines
7.5 KiB
TypeScript

import {
Box,
Button,
Card,
FileInput,
Group,
Stack,
Text,
TextInput,
Textarea,
} from '@mantine/core'
import { notifications } from '@mantine/notifications'
import {
IconDownload,
IconFileTypeDocx,
IconFileTypePdf,
IconFileTypeXls,
IconPhoto,
IconSearch,
IconTrash,
} from '@tabler/icons-react'
import { useState } from 'react'
import classes from './FileUploadForm.module.css'
// type TFileProfile = {
// label: string
// type: string
// value: string
// children?: TFileProfile[]
// }
interface FileData {
id: number
name: string
url: string
type: string
description?: string
created_at: string
}
type FileUploadFormProps = {
data: FileData[];
handleSubmit: (e: React.FormEvent, fileName: string, description: string, currentUser: string) => Promise<boolean | void>;
handleFileChange: (file: File | null) => void;
removeFile: (id: number) => Promise<void>;
isLoading: boolean;
currentUser: string;
};
const FileUploadForm = ({
data,
handleSubmit,
handleFileChange,
removeFile,
isLoading,
currentUser,
}: FileUploadFormProps) => {
const [selectedFile, setSelectedFile] = useState<File | null>(null)
const [fileName, setFileName] = useState('')
const [description, setDescription] = useState('')
const [isUploading, setIsUploading] = useState(false)
const [searchTerm, setSearchTerm] = useState('')
const handleFileSelect = (file: File | null) => {
setSelectedFile(file)
handleFileChange(file)
if (file) {
// Set default name as file name without extension
setFileName(file.name.split('.')[0])
}
}
const handleFormSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsUploading(true)
try {
await handleSubmit(e, fileName, description, currentUser)
notifications.show({
title: 'Thành công',
message: 'Tải file lên thành công',
color: 'green',
})
setFileName('')
setDescription('')
setSelectedFile(null)
} catch (error) {
console.error('Error submitting form:', error)
notifications.show({
title: 'Lỗi',
message: 'Không thể tải file lên',
color: 'red',
})
} finally {
setIsUploading(false)
}
}
const getFileIcon = (type: string) => {
switch (type) {
case 'document':
return <IconFileTypeDocx size={16} />
case 'image':
return <IconPhoto size={16} />
case 'spreadsheet':
return <IconFileTypeXls size={16} />
default:
return <IconFileTypePdf size={16} />
}
}
const filteredFiles = data.filter(
(file) =>
file.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
(file.description &&
file.description.toLowerCase().includes(searchTerm.toLowerCase())),
)
return (
<>
{isLoading && (
<div className={classes.loadingOverlay}>
<div className={classes.loadingSpinner} />
</div>
)}
<form onSubmit={handleFormSubmit}>
<Box>
<Text className={classes.sectionTitle}>Tài liệu</Text>
<Box className={classes.fileInputGroup}>
<FileInput
label="Chọn file"
placeholder="Chọn file để tải lên"
accept="image/png,image/jpeg,image/jpg,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet"
onChange={handleFileSelect}
value={selectedFile}
className={classes.fileInput}
/>
<TextInput
label="Tên file"
placeholder="Nhập tên file"
value={fileName}
onChange={(e) => setFileName(e.target.value)}
className={classes.fileNameInput}
required
/>
<Textarea
label="Mô tả"
placeholder="Nhập mô tả cho file"
value={description}
onChange={(e) => setDescription(e.target.value)}
className={classes.descriptionInput}
minRows={3}
/>
<Button
type="submit"
color="blue"
className={classes.saveButton}
disabled={isLoading || isUploading || !selectedFile || !fileName}
loading={isLoading || isUploading}
>
{isLoading || isUploading ? 'Đang xử lý...' : 'Lưu thay đổi'}
</Button>
</Box>
<Box className={classes.fileListContainer}>
<TextInput
placeholder="Tìm kiếm theo tên hoặc mô tả..."
leftSection={<IconSearch size={14} />}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className={classes.searchInput}
/>
<Stack className={classes.fileList} gap="xs">
{filteredFiles.map((file) => (
<Card
key={file.id}
shadow="xs"
padding="xs"
radius="sm"
withBorder
>
<Group justify="space-between" gap="xs" wrap="nowrap">
<Group gap="xs" className={classes.cardContent}>
{getFileIcon(file.type)}
<Box style={{ minWidth: 0 }}>
<Text size="xs" fw={500} className={classes.cardTitle}>
{file.name}
</Text>
{file.description && (
<Text
size="xs"
c="dimmed"
className={classes.cardDescription}
>
{file.description}
</Text>
)}
<Text size="xs" c="dimmed">
Uploaded:{' '}
{new Date(file.created_at).toLocaleDateString()}
</Text>
</Box>
</Group>
<Group gap="xs" wrap="nowrap">
<Button
size="xs"
variant="light"
color="blue"
component="a"
href={`${import.meta.env.VITE_BACKEND_URL}${
import.meta.env.VITE_BACKEND_URL?.includes(
'localhost',
)
? ''
: 'image/'
}${file.url.slice(1)}`}
target="_blank"
>
<Group gap={2}>
<IconDownload size={12} />
</Group>
</Button>
<Button
size="xs"
variant="light"
color="red"
onClick={() => removeFile(file.id)}
>
<Group gap={2}>
<IconTrash size={12} />
</Group>
</Button>
</Group>
</Group>
</Card>
))}
</Stack>
</Box>
</Box>
</form>
</>
)
}
export default FileUploadForm