From f24c394388145103c4dc3faa01637c6811382054 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sun, 30 Jul 2023 19:15:01 +0200 Subject: [PATCH] ui for files manipulation --- src/pages/files/add.jsx | 100 +++++++++++++++++++++++ src/pages/files/file-selector.jsx | 130 ++++++++++++++++++++++++++++++ src/pages/files/file-view.jsx | 37 +++++++++ src/pages/files/index.jsx | 67 +++++++++++++++ 4 files changed, 334 insertions(+) create mode 100644 src/pages/files/add.jsx create mode 100644 src/pages/files/file-selector.jsx create mode 100644 src/pages/files/file-view.jsx create mode 100644 src/pages/files/index.jsx diff --git a/src/pages/files/add.jsx b/src/pages/files/add.jsx new file mode 100644 index 0000000..0022ff4 --- /dev/null +++ b/src/pages/files/add.jsx @@ -0,0 +1,100 @@ +import { Group, Modal, Text, rem, Button, List } from '@mantine/core'; +import { IconUpload, IconPhoto, IconX } from '@tabler/icons-react'; +import { Dropzone, IMAGE_MIME_TYPE, MIME_TYPES } from '@mantine/dropzone'; +import { useState } from 'react'; +import API from '../../services/api'; +import setNotification from '../errors/error-notification'; + +const ModalAddFile = ({ opened, handler, addFiles }) => { + const [files, setFiles] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const validate = (object) => { + setIsLoading(false); + setFiles([]); + addFiles(object); + handler(); + }; + + const addFilesToList = (files) => { + files.forEach((file) => { + setFiles((prev) => [...prev, file]); + }); + }; + + const handleSubmit = () => { + setIsLoading(true); + const formData = new FormData(); + files.forEach((file) => formData.append('file', file)); + API.upload(formData) + .then((res) => { + if (res.status === 200) { + validate(files); + } + }) + .catch((err) => { + setNotification(true, err.message); + setIsLoading(false); + }); + }; + + return ( + validate([])}> + + + + + + Add File + + + + + + addFilesToList(files)} + onReject={(files) => setNotification(true, `Rejected files: ${files.map((file) => file.name)}`)} + maxSize={1024 ** 3} // 1 GB + accept={[IMAGE_MIME_TYPE, MIME_TYPES.mp4]} + > + + + + + + + + + + + +
+ + Drag images here or click to select files + + + Attach as many files as you like, each file should not exceed 1 GB + +
+
+
+ + {files.map((file, index) => ( + {file.name} + ))} + + + + + +
+
+
+ ); +}; + +export default ModalAddFile; diff --git a/src/pages/files/file-selector.jsx b/src/pages/files/file-selector.jsx new file mode 100644 index 0000000..b0f9e79 --- /dev/null +++ b/src/pages/files/file-selector.jsx @@ -0,0 +1,130 @@ +import { Modal, Button, Text, Group, Grid, TextInput, ScrollArea } from '@mantine/core'; +import { IconSearch } from '@tabler/icons-react'; +import { useEffect, useState } from 'react'; +import ModalAddFile from './add'; +import SelectorItem from '../../components/select-item'; +import API from '../../services/api'; +import setNotification from '../errors/error-notification'; + +const ModalFileSelector = ({ opened, handleClose, handleSubmit, ...props }) => { + const [files, setFiles] = useState([]); + const [showAdd, setShowAdd] = useState(false); + const [search, setSearch] = useState(''); + let resfiless = []; + + const toggleShowAdd = () => setShowAdd(!showAdd); + + const clickHandler = (files) => { + if (props.multi) { + // eslint-disable-next-line eqeqeq + const indexfiles = resfiless.findIndex((item) => item._id == files._id); + if (indexfiles === -1) { + resfiless.push(files); + } else { + resfiless.splice(indexfiles, 1); + } + } else { + handleSubmitLocal(files); + } + }; + + const handleSubmitLocal = (files) => { + handleSubmit(props.multi ? resfiless : files); + handleClose(); + }; + + useEffect(() => { + API.getFiles() + .then((res) => { + if (res.status === 200) { + setFiles(res.data); + } + }) + .catch((err) => { + setNotification(true, err.response.data.error); + }); + + return () => {}; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (search.length >= 2) { + API.searchfiles(search) + .then((res) => { + if (res.status === 200) { + setFiles(res.data); + } + }) + .catch((err) => { + setNotification(true, err.response.data.error); + }); + } else if (search.length === 0) { + API.getFiles() + .then((res) => { + if (res.status === 200) { + setFiles(res.data); + } + }) + .catch((err) => { + setNotification(true, err.response.data.error); + }); + } + }, [search]); + + return ( + + + + + + + Select file{props.multi ? 's' : ''} + + + + + + setSearch(e.target.value)} + icon={} + /> + + + {files.map((file) => ( + + ))} + + + + {props.multi && ( + <> + + + + + )} + + {showAdd && ( + setFiles((prev) => [...prev, files])} + /> + )} + + + + ); +}; + +export default ModalFileSelector; diff --git a/src/pages/files/file-view.jsx b/src/pages/files/file-view.jsx new file mode 100644 index 0000000..874896d --- /dev/null +++ b/src/pages/files/file-view.jsx @@ -0,0 +1,37 @@ +import { Card, Divider, Text, Title, Image, Badge, Button, Group } from '@mantine/core'; + +import API from '../../services/api'; + +const FileView = ({ file, onSelect, onDelete, ...props }) => { + const deleteHandler = async () => { + try { + await API.deleteFile(file.id); + onDelete(file.id); + } catch (error) { + console.log(error); + } + }; + + return ( + + + {file?.name + + {file?.name ?? 'File Name'} + + {!props.noSelect ? ( + + ) : ( + <> + )} + + + + ); +}; + +export default FileView; diff --git a/src/pages/files/index.jsx b/src/pages/files/index.jsx new file mode 100644 index 0000000..93de7e5 --- /dev/null +++ b/src/pages/files/index.jsx @@ -0,0 +1,67 @@ +import { Button, Paper, Grid, Text, Title, Group, List, Image, ScrollArea, Center } from '@mantine/core'; +import { useEffect, useState } from 'react'; +import API from '../../services/api'; +import setNotification from '../errors/error-notification'; +import ModalAddFile from './add'; +import FileView from '../files/file-view'; + +const Files = () => { + const [showAddFile, setShowAddFile] = useState(false); + const [files, setFiles] = useState([]); + const toggleShowAddFile = () => setShowAddFile(!showAddFile); + + const handleAddFiles = (files) => { + console.log(files); + }; + + useEffect(() => { + API.getFiles() + .then((res) => { + if (res.status === 200) { + setFiles(res.data); + } + }) + .catch((err) => { + setNotification(true, err.response.data.error); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + <> + + + Files + + + + + + + Files + + {files.map((file) => ( + + + + ))} + + +
+ +
+
+ handleAddFiles(files)} + /> + + ); +}; + +export default Files;