# Handling file uploads and downloads

{% embed url="<https://www.youtube.com/watch?v=wI51DT6Ztmk>" %}
Upload and read a file
{% endembed %}

***

## **Stuck on Your Project? We've Got You Covered!**

Whether you're short on time or need coding expertise, our **Professional Services** team is here to help.

* Fast turnaround times
* Expert developers
* Affordable rates

[Click here to learn more!](https://blog.mern.ai/professional-services)

***

## Setting up Backend

### Upload File

1. Create a '`Blank Backend Function`' file in `main-features` folder and name it as '`upload`'.
2. Paste the below code in '`upload.server.tsx`'

{% code title="upload.server.tsx" %}

```tsx
import {
    createBackendFunction,
    createRequestContext,
    utils,
} from "@magicjs.dev/backend"

export default createBackendFunction(async function () {
    createRequestContext(this)
        .uploader()
        .onFile((info, file) => {
            // Will get the file information from the parameter info.
            utils.saveFileToUserUploads("/", `image.jpg`, file)
        })
})
```

{% endcode %}

* It calls the `uploader` method on the request context, which sets up functionality related to handling file uploads.
* The `onFile` method is called, which sets up an event handler for when a file is uploaded. It takes a callback function `(info, file)` as an argument.
  * `info` contains information about the uploaded file.
  * `file` contains the uploaded file itself.
  * It uses the `utils.saveFileToUserUploads` function to save the uploaded file to a specified location in the user's uploads directory.

This code defines a backend function that handles file uploads. It uses the `createRequestContext` function to create a request context, sets up an uploader, and defines an event handler for handling file uploads.

### Read File

1. Create a '`Blank Backend Function`' file and name it as '`getfile`'.
2. Paste the below code in '`getfile.server.tsx`'

{% code title="getfile.server.tsx" %}

```tsx
import { createBackendFunction, utils } from "@magicjs.dev/backend"

export default createBackendFunction(async function (fileName: string) {

    return utils.readFileFromUserUploads("/", fileName)

})
```

{% endcode %}

* The `readFileFromUserUploads` method from the `utils` module is called with two arguments:
  * `"/"`: This is the path to the user's upload folder.&#x20;
  * `fileName`: This is the name of the file that needs to be read from the specified upload folder.
* The function returns the result of the `readFileFromUserUploads` operation, which represents the content or data of the file being read.

## Integrate in UI

1. Create a '`Blank UI Component`' file in a feature.
2. Name the file '`upload`' and give a suitable path. We are assigning the path: '`/upload`'.
3. Paste the code given below in '`upload.tsx`'.

{% code title="upload.tsx" %}

```typescript
import React from "react"
import { createUploader, createSrc } from "@magicjs.dev/frontend"
import { Button, Input } from "antd"
import uploadServer from "./upload.server"
import getfileServer from "./getfile.server"

const fileSrc = createSrc(getfileServer)

export default function Component(props: any) {
    const { addFiles, upload, readyToUpload, uploadProgress, loading } =
        createUploader(uploadServer)
        
    return (
        <div>
            <Input
                type="file"
                onChange={(e) => {
                    addFiles(e.target.files)
                    // Adds selected files to the uploader instance
                }}
            />
            <Button
                onClick={() => upload()}
                disabled={loading === true || Boolean(readyToUpload) === false}
            >
                Upload: {uploadProgress}%
            </Button>

            <div>
                <img src={fileSrc.getLink("image.jpg")} alt="File Preview" />
            </div>
        </div>
    )
}
```

{% endcode %}

<details>

<summary>Expand for Tailwind styled code.</summary>

```typescript
import React from "react"
import { createUploader, createSrc } from "@magicjs.dev/frontend"
import uploadServer from "./upload.server"
import getfileServer from "./getfile.server"

const fileSrc = createSrc(getfileServer)

export default function Component(props: any) {
  const [isImageSelected, setIsImageSelected] = React.useState(false);
  const [imageName, setImageName] = React.useState('');
  const { addFiles, upload, readyToUpload, uploadProgress, loading } =
    createUploader(uploadServer)

  return (
    <div className="flex flex-row items-center justify-start h-screen gap-10 p-10">
      <div className="flex flex-col gap-3">
        <div className="flex items-center gap-3 w-[300px]">
          <button
            className="h-[35px] font-medium text-[13px] bg-[#FFFFFF] text-[#1C274C] px-4 rounded-[5px] border border-[#E3E3E3] hover:opacity-70 active:scale-95"
            onClick={() => {
              const fileInput = document.getElementById('fileInput');
              if (fileInput) {
                fileInput.click();
              }
            }}
          >
            Choose File
          </button>
          <div className="text-gray-600 text-sm" id="fileInputLabel">
            {isImageSelected ? imageName : `No file chosen yet`}
          </div>
        </div>
        <input
          type="file"
          id="fileInput"
          className="sr-only"
          onChange={(e: any) => {
            const selectedFile = e.target.files?.[0];
            if (selectedFile && selectedFile.name) {
              const fileName = selectedFile.name.length > 20
                ? selectedFile.name.slice(0, 20) + '...'
                : selectedFile.name;

              const fileInputLabel = document.getElementById('fileInputLabel');

              if (fileInputLabel) {
                fileInputLabel.innerText = fileName;
              }
              // Adds selected files to the uploader instance
              addFiles(e.target.files);
              setImageName(fileName)
              setIsImageSelected(true)
            }
          }}
        />
        <button
          className='w-fit text-[20px] text-white bg-violet-500 border border-[#BFBFBF] rounded-[10px] p-3 disabled:bg-violet-300 disabled:cursor-not-allowed hover:opacity-70 active:scale-95'
          onClick={() => upload()}
          disabled={loading === true || Boolean(readyToUpload) === false}
        >
          Upload: {uploadProgress}%
        </button>
      </div>
      <div>
        <img className="w-400" src={fileSrc.getLink("image.jpg")} alt="File Preview" />
      </div>
    </div>
  )
}
```

*The code may have significant modifications to enhance the styling of the input button.*

</details>

* It renders a file input (`Input`) and a button (`Button`) for file selection and upload, respectively.
* The `onChange` event of the file input adds selected files to the uploader instance using the `addFiles` function.
* The upload button is disabled if the `loading` state is `true` or `readyToUpload` is `false`.
* It displays upload progress using the `uploadProgress` state.
* It renders an image tag (`img`) with the source URL obtained from `fileSrc.getLink("image.jpg")`, displaying a preview of the uploaded file.

<figure><img src="https://629398272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrhfVeNvXQhNiRfJxJ9pq%2Fuploads%2FzkKH94vt3SDXsl3TdBWG%2FScreenshot%202024-03-26%20at%2012.19.40%20PM.png?alt=media&#x26;token=69ede46a-6d98-4f2c-bc56-b0172a178838" alt=""><figcaption><p>Output - Preview of the uploaded image</p></figcaption></figure>

{% hint style="info" %}
Choose a file to upload and click on the button '`Upload`'. Refresh the page to view the uploaded file.
{% endhint %}

***

## **Ready to step into the role of a Product Owner?**

Dive into our comprehensive course designed to equip you with the skills and knowledge needed to excel. [Click here](https://university.mern.ai/) to embark on your journey towards becoming a proficient product owner and unlocking exciting career opportunities!

***
