Let's create a React File Manager Chapter XIII: Organizing files
Tags: react, typescript, mongez, javascript
Published: 2022-09-15 07:30:14

---
title: Let's create a React File Manager Chapter XIII: Organizing files
published: true
description: 
series: File Manager React Mongez
tags: react, typescript, mongez, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aaxrogi0uf39gqllexjt.png
# Use a ratio of 100:42 for best results.
---

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.

```tsx
// 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

```tsx

// FileManager.types.ts
import { Node } from "../../types/FileManager.types";

export type FileManagerProps = {
  /**
   * Root path to open in the file manager
   *
   * @default "/"
   */
  rootPath?: string;
  ...
};
```

After

```ts
// 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.

```ts
// 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:

![[File Structure]](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkdgi9t7ttkhqq4wshgf.png)

## 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:

![Imports](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11qh2rnx3856d564bsoh.png)

```tsx
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.

```tsx
// hooks/index.ts
export { default as useKernel } from "./useKernel";
export { default as useLoading } from "./useLoading";
```

```tsx
// contexts/index.ts
export { default as KernelContext } from "./KernelContext";
```

```tsx
// 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

```tsx
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.

```tsx
// 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 (
    <>
      <Helmet title="home" appendAppName={false} />
      
👉🏻      <FileManager />
    </>
  );
}
```

Now we're gooooood, everything is clean and shiny.

## Article Repository

You can see chapter files in [Github Repository](https://github.com/hassanzohdy/file-manager-react/tree/13-organizing-files)

> 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.