This chapter is about organizing files in a way that makes more sense and easy to understand.
It will also be a light one, and we'll be playing around in everywhere.
Let's do some colors first
Before we jump to cleaning the code, let's add some fancy colors to our LoadingProgressBar
component, also let's add label to indicate the current loading percentage.
// LoadingProgressBar.tsx
import { Progress } from "@mantine/core";
import { useEffect, useState } from "react";
import useFileManager from "../../hooks/useFileManager";
export default function LoadingProgressBar() {
const fileManager = useFileManager();
const [progress, setProgress] = useState(0);
useEffect(() => {
// let's create an interval that will update progress every 300ms
let interval: ReturnType<typeof setInterval>;
// we'll listen for loading state
const loadingEvent = fileManager.on("loading", () => {
setProgress(5);
interval = setInterval(() => {
// we'll increase it by 10% every 100ms
// if it's more than 100% we'll set it to 100%
setProgress(progress => {
if (progress >= 100) {
clearInterval(interval);
return 100;
}
return progress + 2;
});
}, 100);
});
// now let's listen when the loading is finished
const loadEvent = fileManager.on("load", () => {
// clear the interval
setProgress(100);
setTimeout(() => {
clearInterval(interval);
// set progress to 0
setProgress(0);
}, 300);
});
// unsubscribe events on unmount or when use effect dependencies change
return () => {
loadingEvent.unsubscribe();
loadEvent.unsubscribe();
};
}, [fileManager]);
const mapProgressColor = () => {
if (progress < 25) {
return "blue";
}
if (progress < 50) {
return "indigo";
}
if (progress < 75) {
return "lime";
}
return "green";
};
return (
<Progress
size="lg"
value={progress}
striped
label={progress > 0 ? `${progress}%` : undefined}
color={mapProgressColor()}
animate
/>
);
}
I'll not say much here, the code is self-explanatory.
Encapsulations
As we saw over the previous chapters, we added more components, and some of these components have their own types and styles, so let's create a directory for each of these components.
We will export all components that are located in src/apps/front-office/file-manager/components/FileManager
to be directly in components
directory.
Relative Paths
Before we do this, we need to change all relative paths that are outside of current directory to be absolute paths.
For example, File Manager types.
Before
// FileManager.types.ts
import { Node } from "../../types/FileManager.types";
export type FileManagerProps = {
/**
* Root path to open in the file manager
*
* @default "/"
*/
rootPath?: string;
...
};
After
// FileManager.types.ts
import { Node } from "app/file-manager/types/FileManager.types";
export type FileManagerProps = {
/**
* Root path to open in the file manager
*
* @default "/"
*/
rootPath?: string;
...
};
And so on for the rest of the files.
I don't really like relative paths, let's make it absolute, i'll skip it in the article but you can see it in the repository's branch.
Sidebar
Let's start with Sidebar
component.
Create Sidebar.types.ts
file and move all types related to Sidebar
component to it.
We need to move it to be directly in components
directory.
// Sidebar.types.ts
import { Node } from "../../../types/FileManager.types";
export type SidebarProps = {
rootDirectory?: Node;
};
Now we remove the type block from the Sidebar
component and just import our new type.
We will also create a separate directory for SidebarNode
but it will be inside Sidebar
directory.
Now the final structure will look like this:
Kernel
As we have two identical names, the FileManager
that makes all operations and FileManager
component, we need to rename the FileManager
component to Kernel
.
We will also move all types related to Kernel
to Kernel.types.ts
file.
We'll create a directory for it and move all related files to it.
We also will rename the context to be KernelContext
and the hook to be useKernel
.
Now we'll go through all files and update it properly.
I advice you to see it in the repository so you know what you'll update.
Indexes for each directory
If we checked the FileManager
component imports, we'll see it after previous modifications as follows:
import { Grid } from "@mantine/core";
import Content from "app/file-manager/components/Content";
import LoadingProgressBar from "app/file-manager/components/LoadingProgressBar";
import Sidebar from "app/file-manager/components/Sidebar";
import Toolbar from "app/file-manager/components/Toolbar";
import KernelContext from "app/file-manager/contexts/KernelContext";
import Kernel, { Node } from "app/file-manager/Kernel";
ΩSo components have multiple levels, contexts hooks and kernel itself.
We can make it easier by creating an index.ts
file in each directory and export all components from it.
// hooks/index.ts
export { default as useKernel } from "./useKernel";
export { default as useLoading } from "./useLoading";
// contexts/index.ts
export { default as KernelContext } from "./KernelContext";
// components/index.ts
export { default as Content } from "./Content";
export { default } from "./FileManager";
export * from "./Sidebar";
export { default as Sidebar } from "./Sidebar";
export { default as Toolbar } from "./Toolbar";
Now we can directly call our imports like this
import { useLoading } from "app/file-manager/hooks";
import { Node } from "app/file-manager/Kernel";
Top index for the entire file manager
Let's create an index.ts
file in app/file-manager
directory and export all components from it.
// app/file-manager/index.ts
export * from "./components";
export { default } from "./components";
export * from "./contexts";
export * from "./hooks";
export * from "./Kernel";
export { default as Kernel } from "./Kernel";
Be Careful with the internal imports and circular dependencies
Don't make all imports from the index files as some files will have circular dependencies, for example in FileManager
component we can not call LoadingProgressBar
from components/index
but we have to call it directly `app/front-office/file-manager/components/LoadingProgressBar.
Finally let's update our import in HomePage
component
`tsx
// HomePage.tsx
import Helmet from "@mongez/react-helmet";
ππ» import FileManager from "app/file-manager";
export default function HomePage() {
return (
<>
ππ»
</>
);
}
`
Now we're gooooood, everything is clean and shiny.
Article Repository
You can see chapter files in Github Repository
Don't forget the
main
branch has the latest updated code.
Tell me where you are now
If you're following up with me this series, tell me where are you now and what you're struggling with, i'll try to help you as much as i can.
Salam.
Top comments (0)