Skip to content

Commit

Permalink
Merge pull request #69 from Saifullah-dev/refactor/code-splitting
Browse files Browse the repository at this point in the history
Additional props for better customization
  • Loading branch information
Saifullah-dev authored Sep 19, 2024
2 parents bc2d68a + 5c3282d commit cefe031
Show file tree
Hide file tree
Showing 31 changed files with 464 additions and 140 deletions.
72 changes: 46 additions & 26 deletions README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions backend/app/controllers/fileSystem.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const copyItem = require("./handlers/copyItem.handler");
const moveItem = require("./handlers/moveItem.handler");
const renameItem = require("./handlers/renameItem.handler");
const deleteItem = require("./handlers/deleteItem.handler");
const downloadFile = require("./handlers/downloadFile.handler");

module.exports = {
createFolder,
Expand All @@ -14,4 +15,5 @@ module.exports = {
moveItem,
renameItem,
deleteItem,
downloadFile,
};
21 changes: 21 additions & 0 deletions backend/app/controllers/handlers/downloadFile.handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const FileSystem = require("../../models/FileSystem.model");
const path = require("path");

const downloadFile = async (req, res) => {
try {
const { id } = req.params;

const file = await FileSystem.findById(id);
if (!file || file.isDirectory) {
res.status(404).json({ error: "File not found!" });
}

const filePath = path.join(__dirname, "../../../public/uploads", file.path);
res.header("Access-Control-Expose-Headers", "Content-Disposition");
res.download(filePath, file.name);
} catch (error) {
res.status(500).json({ error: error.message });
}
};

module.exports = downloadFile;
1 change: 1 addition & 0 deletions backend/app/routes/fileSystem.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ router.post("/copy", fileSystemController.copyItem);
router.put("/move", fileSystemController.moveItem);
router.patch("/rename", fileSystemController.renameItem);
router.delete("/:id", fileSystemController.deleteItem);
router.get("/download/:id", fileSystemController.downloadFile);

module.exports = router;
72 changes: 46 additions & 26 deletions frontend/README.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"semantic-release": "^24.1.0",
"vite": "^5.3.1"
},
"description": "The File Manager Component is an open-source React.js package designed to help developers easily integrate a file manager into their applications. This component provides a user-friendly interface along with essential functionalities for managing files and folders, such as viewing, uploading and deleting within a specified directory structure. Ideal for anyone looking to build or enhance a file management system, this package offers both UI and backend integration capabilities.",
"description": "React File Manager is an open-source, user-friendly component designed to easily manage files and folders within applications. With smooth drag-and-drop functionality, responsive design, and efficient navigation, it simplifies file handling in any React project.",
"main": "src/index.js",
"repository": {
"type": "git",
Expand All @@ -47,7 +47,8 @@
"keywords": [
"react",
"file-manager",
"component"
"component",
"react-file explorer"
],
"author": "Saifullah Zubair",
"license": "MIT",
Expand Down
23 changes: 21 additions & 2 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { renameAPI } from "./api/renameAPI";
import { deleteAPI } from "./api/deleteAPI";
import { copyItemAPI, moveItemAPI } from "./api/fileTransferAPI";
import { getAllFilesAPI } from "./api/getAllFilesAPI";
import { downloadFile } from "./api/downloadFileAPI";
import "./App.scss";

function App() {
Expand Down Expand Up @@ -102,6 +103,18 @@ function App() {
};
//

const handleFileOpen = (file) => {
console.log(`Opening file: ${file.name}`);
};

const handleError = (error, file) => {
console.error(error);
};

const handleDownload = async (file) => {
await downloadFile(file._id);
};

return (
<div className="app">
<div className="file-manager-container">
Expand All @@ -112,13 +125,19 @@ function App() {
onCreateFolder={handleCreateFolder}
onFileUploading={handleFileUploading}
onFileUploaded={handleFileUploaded}
onPaste={handlePaste}
onRename={handleRename}
onDownload={handleDownload}
onDelete={handleDelete}
onPaste={handlePaste}
onLayoutChange={handleLayoutChange}
onRefresh={handleRefresh}
onFileOpen={handleFileOpen}
onError={handleError}
layout="grid"
enableFilePreview
maxFileSize={10485760}
filePreviewPath={import.meta.env.VITE_API_FILES_BASE_URL}
allowedFileExtensions=".txt, .png, .jpg, .jpeg, .pdf, .doc, .docx"
acceptedFileTypes=".txt, .png, .jpg, .jpeg, .pdf, .doc, .docx, .exe"
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ body {
height: 70%;
width: 67%;
}
}
}
6 changes: 4 additions & 2 deletions frontend/src/FileManager/Actions/Actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const Actions = ({
onFileUploading,
onFileUploaded,
onDelete,
maxFileSize,
filePreviewPath,
allowedFileExtensions,
acceptedFileTypes,
triggerAction,
}) => {
const [activeAction, setActiveAction] = useState(null);
Expand All @@ -23,7 +24,8 @@ const Actions = ({
component: (
<UploadFileAction
fileUploadConfig={fileUploadConfig}
allowedFileExtensions={allowedFileExtensions}
maxFileSize={maxFileSize}
acceptedFileTypes={acceptedFileTypes}
onFileUploading={onFileUploading}
onFileUploaded={onFileUploaded}
/>
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/FileManager/Actions/Delete/Delete.action.scss
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
.file-delete-confirm {
.file-delete-confirm-text {
border-bottom: 1px solid #dddddd;
padding: 10px 15px;
margin-bottom: 1rem;
padding: 15px;
margin-top: 0;
margin-bottom: .7rem;
word-wrap: break-word;
font-weight: 500;
}

.file-delete-confirm-actions {
display: flex;
gap: 0.5rem;
justify-content: flex-end;
margin-bottom: 1rem;
margin-bottom: .7rem;
margin-right: 1rem;
}
}
11 changes: 10 additions & 1 deletion frontend/src/FileManager/Actions/Rename/Rename.action.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const RenameAction = ({ filesViewRef, file, onRename, triggerAction }) => {
show={renameFileWarning}
setShow={setRenameFileWarning}
dialogWidth={"25vw"}
closeButton={false}
>
<div className="fm-rename-folder-container" ref={warningModalRef}>
<div className="fm-rename-folder-input">
Expand All @@ -180,8 +181,16 @@ const RenameAction = ({ filesViewRef, file, onRename, triggerAction }) => {
<Button
type="secondary"
onClick={() => {
setCurrentPathFiles((prev) =>
prev.map((f) => {
if (f.key === file.key) {
f.isEditing = false;
}
return f;
})
);
setRenameFileWarning(false);
outsideClick.setIsClicked(false);
triggerAction.close();
}}
>
No
Expand Down
86 changes: 64 additions & 22 deletions frontend/src/FileManager/Actions/UploadFile/UploadFile.action.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,89 @@ import Button from "../../../components/Button/Button";
import { AiOutlineCloudUpload } from "react-icons/ai";
import UploadItem from "./UploadItem";
import ReactLoading from "react-loading";
import "./UploadFile.action.scss";
import { useFileNavigation } from "../../../contexts/FileNavigationContext";
import { getFileExtension } from "../../../utils/getFileExtension";
import { getDataSize } from "../../../utils/getDataSize";
import { useFiles } from "../../../contexts/FilesContext";
import "./UploadFile.action.scss";

const UploadFileAction = ({
fileUploadConfig,
allowedFileExtensions,
maxFileSize,
acceptedFileTypes,
onFileUploading,
onFileUploaded,
}) => {
const [files, setFiles] = useState([]);
const [isDragging, setIsDragging] = useState(false);
const [isUploading, setIsUploading] = useState({});
const { currentFolder } = useFileNavigation();
const { currentFolder, currentPathFiles } = useFileNavigation();
const { onError } = useFiles();

// Todo: Also validate allowed file extensions on drop
const handleDrop = (e) => {
e.preventDefault();
setIsDragging(false);
const droppedFiles = Array.from(e.dataTransfer.files);
if (droppedFiles.length > 0) {
const choosenFiles = droppedFiles.map((file) => {
const checkFileError = (file) => {
const extError = !acceptedFileTypes.includes(getFileExtension(file.name));
if (extError) return "File type is not allowed.";

const fileExists = currentPathFiles.some(
(item) => item.name.toLowerCase() === file.name.toLowerCase() && !item.isDirectory
);
if (fileExists) return "File already exists.";

const sizeError = file.size > maxFileSize;
if (sizeError) return `Maximum upload size is ${getDataSize(maxFileSize, 0)}.`;
};

const setSelectedFiles = (selectedFiles) => {
selectedFiles = selectedFiles.filter(
(item) =>
!files.some((fileData) => fileData.file.name.toLowerCase() === item.name.toLowerCase())
);

if (selectedFiles.length > 0) {
const newFiles = selectedFiles.map((file) => {
const appendData = onFileUploading(file, currentFolder);
const error = checkFileError(file);
error && onError({ type: "upload", message: error }, file);
return {
file: file,
appendData: appendData,
...(error && { error: error }),
};
});
setFiles((prev) => [...prev, ...choosenFiles]);
setFiles((prev) => [...prev, ...newFiles]);
}
};

// Todo: Also validate allowed file extensions on drop
const handleDrop = (e) => {
e.preventDefault();
setIsDragging(false);
const droppedFiles = Array.from(e.dataTransfer.files);
setSelectedFiles(droppedFiles);
};

const handleChooseFile = (e) => {
const selectedFiles = Array.from(e.target.files);
if (selectedFiles.length > 0) {
const choosenFiles = selectedFiles.map((file) => {
const appendData = onFileUploading(file, currentFolder);
return {
file: file,
appendData: appendData,
};
const choosenFiles = Array.from(e.target.files);
setSelectedFiles(choosenFiles);
};

const handleFileRemove = (index) => {
setFiles((prev) => {
const newFiles = prev.map((file, i) => {
if (index === i) {
return {
...file,
removed: true,
};
}
return file;
});
setFiles((prev) => [...prev, ...choosenFiles]);
}

// If every file is removed, empty files array
if (newFiles.every((file) => !!file.removed)) return [];

return newFiles;
});
};

return (
Expand All @@ -72,7 +112,7 @@ const UploadFileAction = ({
className="choose-file-input"
onChange={handleChooseFile}
multiple
accept={allowedFileExtensions}
accept={acceptedFileTypes}
/>
</Button>
</div>
Expand All @@ -95,9 +135,11 @@ const UploadFileAction = ({
index={index}
key={index}
fileData={fileData}
setFiles={setFiles}
fileUploadConfig={fileUploadConfig}
setIsUploading={setIsUploading}
onFileUploaded={onFileUploaded}
handleFileRemove={handleFileRemove}
/>
))}
</ul>
Expand Down
Loading

0 comments on commit cefe031

Please sign in to comment.