paint-brush
Build a Web3 Movie Streaming dApp using NextJs, Tailwind, and Sia Renterdby@daltonic
1,368 reads
1,368 reads

Build a Web3 Movie Streaming dApp using NextJs, Tailwind, and Sia Renterd

by Darlington Gospel August 23rd, 2024
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

Learn how to build a cutting-edge Web3 movie streaming dApp using NextJs, TypeScript, Tailwind CSS, and Sia Renterd. This tutorial series will guide you in creating a decentralized application that leverages Sia's blockchain technology to ensure user data ownership and privacy.
featured image - Build a Web3 Movie Streaming dApp using NextJs, Tailwind, and Sia Renterd
Darlington Gospel  HackerNoon profile picture


Introduction

The web is evolving, and Web3 technologies are revolutionizing traditional industries, including video streaming. Platforms like Odysee are leading the charge, offering decentralized alternatives to YouTube and Rumble. Similarly, unlike legacy providers like Google Drive and Dropbox, Sia is transforming data storage, providing a privacy-focused and user-centric approach.


Join us on a journey to build a cutting-edge Web3 movie streaming dApp using NextJs, TypeScript, Tailwind CSS, and Sia Renterd. This tutorial series will guide you in creating a decentralized application that leverages Sia's blockchain technology to ensure user data ownership and privacy.


By the end of this tutorial, you'll gain the expertise to:

  • Build a fully functional movie streaming platform to share with friends or use as a school project
  • Launch your own SaaS (Software as a Service) application
  • Unlock the potential of Web3 technologies in the video streaming industry


Watch the demo video below to see the project in action, and subscribe to our channel for more innovative content like this!

Prerequisites

To follow along, ensure you have the following tools installed, and familiarity with the stacks will also enhance your understanding:

  • NodeJs
  • NextJs
  • Tailwind CSS
  • TypeScript
  • Docker (required)


This three-part series will cover:

  • Part 1: Project Setup - Renterd Zen testnet, Package Installations, and environment variables.
  • Part 2: Backend Development - Building the Backend Service
  • Part 3: Frontend Development - Integrating the Frontend with the Backend service.


If you prefer watching the entire development process, I recommend watching this playlist, in the playlist, everything that is written here and more are captured in the videos.


With that said, let’s jump into setting up this project.

Project Setup – Part 1

We'll start by cloning a prepared repository that includes the Sia Renterd docker compose script and the backend and frontend services. Run the following commands:


$ git clone https://github.com/Daltonic/sia_vid_tv
$ cd sia_vid_tv


Now, it's crucial that we switch to our starter branch on this newly cloned GitHub project and run the command below to complete that.


$ git checkout 01_starter_branch


Next, let’s set up the associated environment variable for this Renterd service. Create a .env file at the root of this project and apply the keys below:


RENTERD_SEED=<RENTERD_SEED_PHRASE>
RENTERD_API_PASSWORD=<YOUR_PREFERED_PASSWORD>
RENTERD_LOG_LEVEL=debug
RENTERD_LOG_DATABASE_LEVEL=error


To get these API keys, you will need to have Sia Renterd installed on your machine; please watch the short video below, which pretty much summarizes it all.


Generate a seed phrase with the Renterd application as seen in the above video, and include it inside your environment variable as instructed in the above video. Replace the password with something you can easily remember.


Next, we need to install Docker by downloading it from the official website if you haven't already. Alternatively, use a free online platform like Gitpod or a VPS to run a Docker instance, if possible. Otherwise, install it on your local computer.


Finally, we can spin up a docker container by running the following docker command at the root of this project. Ensure that the terminal is at the same directory location as this docker-compose.yml file.


$ docker compose -f "docker-compose.yml" up -d --build


Note the command to pull down the container: $ docker compose -f "docker-compose.yml" down. Run this when you want to shut down your Docker instance (but not now).


If you performed the above instructions correctly, you should see the interface below when you visit your browser at http://localhost:9880.


Sia Renterd Login interface


Enter your password (from your environment variable) to log in. Then, follow the configuration procedure in the video below to set up your Sia Renterd instance for file uploads, downloads, and streaming.

The above video starts at the 6:41 minute mark, please stop at the 20:01 mark, this part will visually guide you through the Renterd configuration process.


Take note that the blockchain synchronization process, along with host matching, takes up to 25 min to be ready, so you will have to be patient with the whole process.


Please create a new bucket on Renterd called vidtv, where all our files for this project will be stored. If you have executed the above instructions successfully, your Renterd node should be ready for upload and download. See the image below.


Renterd on Zen testnet


Amazing. At this point, our Renterd service is ready to start receiving files, but we need to communicate with it programmatically.

Let's round this part one of this tutorial by having the packages and environment variables set up for the backend and frontend.


Backend Project Setup Perform the following instructions to have the backend service packages installed and ready for further development.

Navigate to the backend directory from a new terminal instance using the following commands:


$ cd backend
$ yarn install #you can also use npm install
$ touch .env #or mannually create it at the root of the backend directory


Next, supply the following information into the environment variables.


SIA_API_BUCKET=vidtv
SIA_API_PASSWORD=<YOUR_PREFERED_PASSWORD>
SIA_API_BASE_URL=http://localhost:9880
ORIGIN=http://localhost:9000
PORT=9000


And now, run $ yarn build && yarn start to spin up the backend and to also confirm that it's free from any bugs.


Frontend Project Setup Lastly, run the following commands to install the packages associated with the frontend. Afterward, we will run it.

Navigate to the backend directory from a new terminal instance using the following commands:


$ cd frontend
$ yarn install #you can also use npm install
$ touch .env #or mannually create it at the root of the backend directory


Next, supply the following information into the environment variables.


NEXT_PUBLIC_PROJECT_ID=<YOUR_WALLET_CONNECT_ID>
NEXT_PUBLIC_FILE_SERVICE_URL=http://localhost:9000


Sign up and create a project with Walletconnect to get your project ID. After you have supplied the project ID to the environment variable, run $ yarn build && yarn start to spin up the backend and to also confirm that it's free from any bug.


At this point, you will see the interface below when you visit the browser at http://localhost:3000.


VidTv Homepage

Movie Poster

Next Step Congratulations on reaching this milestone! Proceed to Part 2 to complete the backend service development.



The Backend Service – Part 2

Welcome Back! Please read through Part 1 if you haven't already. Now, let's dive into Part 2: Building the backend service for our web3 movie streaming platform.

We've provided a starter code for the backend, which currently displays a "Welcome" message when you start the server and visit http://localhost:9000 in your browser. Let's build on this foundation.

We currently have these codes in the backend source directory. Let me briefly explain them to you.

Utility Files This folder which can be fully addressed to backend/src/utils contains two essential files: an HTTP exception handler function and an interface for handling file upload information.

This code defines a custom HttpException class that extends the built-in JavaScript Error class, allowing error instances to be created with specific HTTP status codes and messages.

This code defines an interface FileUpload that represents an uploaded file, specifying its properties such as name, data, size, encoding, and more, providing a structured way to handle file uploads in this backend application.

And then at backend/src root folder, we have this index.ts file which sets up an Express.js server with CORS and file upload support, defines a single GET route that returns a "Welcome" message, and handles errors by catching and re-throwing them as custom HttpExceptions, then starts the server on the port 9000 as specified in the environment variables.

Now that we've covered the key files, let's create two new files in a services folder, each serving a distinct purpose in our application.

Service Files

In the backend/src folder, make a new folder called services in this location, this is where we'll create two services:

  1. Sia Service: Handles file uploads, downloads, streaming, and caching, communicating with the Renterd service.
  2. Background Service: Manages cached files, automatically removing them after 7 days at midnight daily.

The Sia Service

Let’s create a file named sia.service.ts at the backend/src/services folder and follow the steps below to formulate this service.

This code defines a SiaService class that initializes with environment variables for Sia API settings and an origin URL, providing a foundation for managing interactions with the Sia service. Now, let's supply the rest of the codes for this service.


Uploading Files to Sia Renterd To upload files to the Sia Network, we will need to add these three methods into the class, two will be private whereas one will be public.

This code defines a private method generateRandomString that generates a random string of a specified length, composed of uppercase and lowercase letters and numbers, using a loop to select characters randomly from a predefined string. We will use it to rename each file uniquely before shipping a file to Renterd.

The above code defines a private method uploadToSiaService that uploads a file to Sia Renterd using Axios, handling upload progress and errors, and returning the Axios response or throwing an error if the upload fails.


The Renterd endpoints are written in the API documentation which you can check out or watch the video below where I explained how the Sia Renterd API documentation.

Now let’s include the public method which we will later expose as an endpoint in our application.

This code defines a public method uploadFile that uploads a file by generating a unique identifier, saving the file to a local cache, and then uploading it to the Sia Renterd, returning the file's URL and a success message or throwing an error if the upload fails.


Downloading Files to Sia Renterd To download files to the Sia Network, we will need to add these two methods into the class, one will be private and the other will be public.

This code defines a private method downloadFromSiaService that retrieves a file from the Sia service, caches it locally, and returns a readable stream of the file, handling errors and returning a 404 image if the file is not found.


Let’s have those response_files available in the backend directory, else we will experience an error calling the 404.png file. At the backend directory create another folder called response_files and copy the following images into it.


404.png

401.png

Perfect, now let’s complete this file download service. Also add the method below in the SiaService class.

This code defines a public method downloadFile that calls the private method downloadFromSiaService to retrieve a file from the Sia Renterd and returns the readable stream of the retrieved file.

Service Endpoints

It's time we couple these various methods to their respective endpoints, currently, we have just one, but we will need an additional two for uploading and downloading files. File streaming will also utilize the download endpoint.


Head to the backend/src/index.ts file and update its content with these codes.

This code sets up an Express.js server with CORS and file upload support, defining three endpoints: a welcome message, file upload to the Sia Network, and file download from the Sia Network, using the SiaService class to handle file operations and HttpException for error handling.


Watch this section of the video below if you require some visual aid, ensure you stop at the 01:50:44 timestamp.

We need to create a cache management service to ensure our server doesn't fill up with unused files by controlling how long files stay in the cache. It’s important to know that the only reason we needed this service is to reduce data latency.

The Background Service

Head to the backend/src/services folder and create a file called background.service.ts and add these sequences of code to it.

This code defines a BackgroundService class that sets up a cache directory and schedules daily jobs using the node-cron library, initializing the background jobs and logging a confirmation message. Let’s create a method that will be responsible for deleting files older than 7 days in the cache.


Deleting Old File Add this method to the BackgroundService class.

This code defines a method called deleteOldFiles that removes files from a cache directory that are older than 7 days, by reading the directory, checking each file's creation time, removing files that exceed the target time, logging the start and end of the job, and any errors or successful deletions.


Now, let’s write a function that will utilize the node-cron package to schedule when to execute the file deletion.

This code sets up a daily cron job to run the deleteOldFiles method every day at midnight (00:00) to perform automatic file cleanup.

We also need to update the constructor function to schedule the daily Jobs at the instantiation of the background service class.

Perfect, lastly, let’s add this background operation as part of the server process at initialization. Head to the backend/src/index.ts file, and update the app listener method to import the background service file.

You should rerun the backend service command using $ yarn build && yarn start and see a terminal printout like the one in the image below.


Observe the console log from the Background Service

If you would rather watch how I coded the entire background service, the video below is for you; just ensure you stop at the 02:16:07 timestamp.

Next Step Congratulations, you are now ready for the final part of this tutorial which is Part 3.



Let's dive into the final part of this tutorial series, where we'll integrate the backend with the Frontend, connecting the pieces to complete the file upload application. We will begin by ensuring that authentications in the Frontend are up and running.

Web3 Modal Authentication – Part 3

Create a new folder named 'config' in the Frontend directory and add an index file, resulting in the path /frontend/config/index.tsx. Now, let’s add the following codes to it.

This code sets up a Wagmi configuration for our Web3 application, defining metadata, supported chains, and authentication settings, including wallet and social login options, and stores it in the config export. We also need to create a context API to keep track of the authentication state.


The Context API Next, create a new folder named 'context' still in the Frontend directory and add an index file, resulting in the path /frontend/context/index.tsx. Add the following codes to it.

This code sets up a Web3Modal provider using Wagmi and React Query, configuring the Web3 modal with the project ID and theme variables and wrapping the application in a WagmiProvider and QueryClientProvider.


Updating Layout: Let’s have our application layout updated to include the above configurations. Head to /frontend/app/layout.tsx and replace its codes with the one below.

The above code sets up the root layout for a Next.js application, including metadata, fonts, styles, and providers for Web3 modal, toast notifications, and layout components like header and footer.


The Login Button Now, we need to enable the login buttons in the /frontend/app/components/layout/Header.tsx and /frontend/app/components/shared/Menu.tsx components, and update their codes using the information below.

This code defines a React component for a navigation bar that includes a logo, navigation links, a custom menu, and a login button that launches a Web3 Modal with a responsive design for different screen sizes.


The following images should pop up as proof that what we have done works when you click on the login button and proceed with your preferred provider, X, Facebook, Google, Discord, or Ethereum.


Before Authentication

After Authentication

Superb, let’s go deeper and set up our database and NextJs API-based system. For any confusion on the process, please watch the video section below; just make sure you stop at the 02:57:59 mark.

Database Scripts

First, let’s update the NextJs configuration script to properly address our pages and endpoints and free our remote images from warnings and scrutiny.

This code defines a Next.js configuration object that sets up API route rewrites and image optimization, allowing remote images from any HTTPS hostname and local images from the localhost domain.


Database Config Script We will be using SQLite for this application, but you are free to use a more robust solution such as MYSQL or NOSQL providers. For the sake of simplicity, let's work with a SQLite flat file.


Create /frontend/app/api/database.ts file path and add the codes below to it.

This code sets up an SQLite database connection, defines two API functions, apiGet and apiPost, to perform GET and POST requests on the database, with error handling and promise-based asynchronous execution. We will be using these codes whenever we wish to send or retrieve data from the database.


Database Migration Script We need to create both a database flat file and a table to hold all our contents. Create /frontend/app/api/migrations.ts file path and add the codes below to it.

This code defines a database migration function that creates a 'movies' table with specified columns if it doesn't exist, using SQLite, and logs the result of the operation. Now run the command below in a terminal pointed at the /frontend directory.


$ cd frontend
$ npx esrun app/api/migrations.ts


It should be noted that this process will also create a database flat file called movies.db at the root of the frontend directory. We have also added this command to the package.json script, so running $ yarn migrate on the frontend directory should work the same.


For visual assistance, watch the video below, just stop it at the 03:10:54 mark.

Application Endpoints

Now, let’s define some endpoints for creating, reading, updating, and deleting movies. We will be using the NextJs API provision to make these endpoints.


Create Movie Endpoint To create a movie, the required information includes the user ID, movie name, image, video URL, release date, genre, rating, language, duration, and background description. Create /frontend/app/api/movies/create/route.ts file path and add the codes below to it.

This code defines an endpoint to handle POST requests, validate and process movie data, generate a unique slug, and insert the data into a database using an apiPost function while handling errors and returning JSON responses.


Update Movie Endpoint To update a movie, the required information includes the user ID, slug, and other information provided when creating a movie. Create /frontend/app/api/movies/update/route.ts file path and add the codes below to it.

This code defines an endpoint to handle POST requests for updating a movie, validating required properties, and executing an SQL query to update the movie data in the database using the apiPost function.


Delete Movie Endpoint To delete a movie, the required information includes the user ID and slug of a movie. Create /frontend/app/api/movies/delete/route.ts file path and add the codes below in it.

This code defines an endpoint to handle POST requests for deleting a movie, validating required properties (userId and slug), and executing an SQL query to delete the movie from the database using the apiPost function.


All Movies Endpoint The optional data required to get movies are pageSize and userId, which can be passed as query parameters to filter and paginate the results. Create /frontend/app/api/movies/all/route.ts file path and add the codes below to it.

The above code defines an endpoint to handle GET requests for retrieving movies, allowing optional filtering by userId and pagination by pageSize, and returns the results in JSON format.


Single Movie Endpoint To retrieve a single movie, the required data is the slug of a movie. Create /frontend/app/api/movies/[slug]/route.ts file path and add the codes below to it.

This code defines an endpoint to handle GET requests for retrieving a movie by its slug, validating the slug parameter, and executing an SQL query to retrieve the movie data from the database using the apiGet function.


That marks all the endpoints we will need for this application. If you need a visual aid to help you understand these endpoints better, please watch the video below, just ensure you stop at the 03:48:22 timestamp.

Endpoint Integration

Our task is to review and update pre-coded components and pages, explaining each one's purpose and functionality and documenting the changes we make to the existing code. We will start by creating a service for interacting with the endpoints we previously created in the api directory.


Create /frontend/app/services/api.service.ts file path and add the codes below to it.

This service provides a set of functions to interact with a movie database, allowing the application to fetch movies, fetch a single movie by slug, create a new movie, update an existing movie, delete a movie, and upload files using API requests and handling errors.

Application Pages

Let’s review and update the various pages associated with our application. You wouldn’t need to change many things, just the ones highlighted here.


Create Movie Page

Create Movie Page

This page is a movie publishing form that allows users to upload video and image files, input movie details, and submit the form to publish the movie, with validation and error handling, using React and Wagmi libraries.


Now, update the file found in /frontend/app/pages/create/page.tsx with the codes below.

The changes made in this code compared to the original one are:

  1. Imported the createMovie function from api.service and used it in the handleSubmit function to create a new movie.
  2. Added the userId parameter to the createMovie function call, passing the user's address from the useAccount hook.
  3. Updated the handleSubmit function to use toast.promise to handle the promise returned by createMovie.
  4. Added error handling to the createMovie function call in the handleSubmit function.


These changes enable the form to submit movie data to the API and create a new movie entry while also handling errors and displaying a success message.


Edit Movie Page

Edit Movie Page Similar to the Create Movie Page

This movie editing page allows authorized users to update movie details, upload posters and videos, and save changes, with validation and error handling, utilizing React, Wagmi, and Next.js, specifically designed for users to edit their movies.


Now, update the file found in /frontend/app/pages/movies/edit/[slug]/page.tsx with the codes below.

The upgrades made to the code that is different from the original are:

  1. Imported fetchMovie and updateMovie functions from @/app/services/api.service and used them in the useEffect hook and handleSubmit function, respectively.
  2. Replaced the posters.find() method with the fetchMovie function to retrieve movie data.
  3. Updated the handleSubmit function to call the updateMovie function with the updated movie details.
  4. Added error handling to the updateMovie function call in the handleSubmit function.


These changes enable our application to interact with our API endpoints to retrieve and update movie data, whereas the original code relied on our local posters array.


Home Page

Home Page

This home page renders the banners component, a list of movies (either from an API source or a loading UI), and subscription options, utilizing React and Next.js, to provide an engaging and informative landing page for users.


Update the file found in /frontend/app/pages/page.tsx with the following codes.

The changes we made to the home page are:

  1. Imported fetchMovies function from ./services/api.service and used it in the useEffect hook to retrieve movie data from our API.
  2. Replaced the local posters data with the fetchMovies function call, which fetches data from our API.
  3. Added await keyword to wait for the promise returned by fetchMovies to resolve before setting the movies state.

These changes help our application to retrieve movie data from our API instead of relying on local data, making the application more dynamic and data-driven.

User Account Page

Account Page

This page displays a list of movies posted by the currently connected user, with a loading skeleton placeholder while the data is being fetched and a message prompting the user to connect their account if they haven't done so, utilizing Wagmi and react-loading-skeleton.


Update the file found in /frontend/app/pages/account/page.tsx with the following codes.

The changes made to the page are:

  1. Imported fetchMovies function from @/app/services/api.service and used it in the useEffect hook to retrieve movie data from our API.
  2. Replaced the local posters data with the fetchMovies function call, which fetches data from our API.
  3. Passed address as an argument to the fetchMovies function to retrieve user-specific movie data.
  4. Removed the conditional check for address before rendering the movie list, as the fetchMovies function now handles this logic.
  5. Simplified the conditional statement for displaying the loading skeleton, as it now only depends on the loaded state.


These changes retrieve movie data from our API, specific to the connected user, and display a loading skeleton while the data is being fetched.


Movies Details Page

Movies Details

This page displays a single movie's details, including its name, release year, rating, duration, genre, and background information, along with a video player and related movies, and provides options to edit or delete the movie if the user is the owner, utilizing Next.js, and Wagmi.


Update the file found in /frontend/app/pages/movies/[slug]/page.tsx with the following codes.

We made some huge changes here! Here's a summary of what we did:

  1. Imported deleteMovie, fetchMovie, and fetchMovies functions from @/app/services/api.service and used them to interact with our API endpoints.
  2. Replaced local data with API calls to retrieve movie data.
  3. Implemented movie deletion functionality using the deleteMovie function.
  4. Used toast.promise to display a notification while deleting a movie.
  5. Removed the posters local data and replaced it with API calls.
  6. Updated the handleSubmit function to call the deleteMovie function and handle the response.
  7. Updated the useEffect hook to call the fetchMovie and fetchMovies functions.


These changes cause our application to interact with our API to retrieve and delete movie data and display notifications to the user during the deletion process.


This part of the video below will show you hands-on how we integrated these pages with the endpoint, please feel free to watch that part if you run into any problem. Just make sure you stop at the 04:57:41 timestamp.

Application Components

Let’s discuss the purpose of each component in our application. We will update any component that needs to be modified.

Banner Component


Banner Component

This component displays a rotating background image of movie banners, cycling through an array of movie images every 5 seconds, creating a simple and automatic slideshow effect. This component code can be assessed at /frontend/app/components/home/Banner.tsx.


Posters Component

Posters Component

This component displays a responsive and interactive carousel of movie posters using the Swiper library, with features like autoplay, pagination, and navigation, showcasing a list of movies passed as a prop, with a dynamic layout adapting to different screen sizes. This component code can be assessed at /frontend/app/components/home/Posters.tsx.


Poster UI Component

Poster UI Component

This component displays a placeholder skeleton layout for a movie posters section, using the react-loading-skeleton library, showing a dynamic number of skeleton posters based on the "posters" prop, with a responsive design adapting to different screen sizes, indicating a loading state until the actual posters data is fetched and displayed. This component code can be assessed at /frontend/app/components/home/PosterUI.tsx.


Subscriptions Component

Subscriptions Component

This component displays a subscription plans section, showcasing various dummy plans with their details, prices, and benefits. It allows users to choose a plan that suits their needs, utilizing a responsive grid layout and interactive hover effects to enhance the user experience. This component code can be assessed at /frontend/app/components/home/Subscription.tsx.


Header Component

The Header Component

This component renders a fixed navigation bar at the top of the page, featuring a logo, a navigation menu with links to various sections, a menu toggle button for responsive design, and a login button, providing a consistent and accessible header section across the application. This component code can be assessed at /frontend/app/components/layout/Header.tsx.


Footer Component

Footer Component

This component renders a footer section at the bottom of the page, featuring the application's logo, a brief description, navigation links, contact information, and a credit mentioning the decentralized storage solution powered by Sia Foundation, providing a clear and organized footer section with relevant information and links. This component code can be assessed at /frontend/app/components/layout/Footer.tsx.


Menu Component

Menu Component

This component renders a responsive menu toggle button, which, when clicked, opens or closes a dropdown menu containing navigation links, allowing users to access various sections of the application on smaller screens while hiding the menu on larger screens where the navigation links are already visible. This component code can be assessed at /frontend/app/components/shared/Menu.tsx.


Movie Card Component

Movie Card Component

This component displays a single movie's poster with a hover effect, showing additional information such as the movie's name, release year, and background summary while also serving as a link to the movie's details page, utilizing a responsive design and animated transitions to enhance the user experience. This component code can be assessed at /frontend/app/components/shared/MovieCard.tsx.


Uploaded Component

Uploaded Component

This component displays a preview of an uploaded file, either an image or a video, with a progress bar and a removal button, allowing users to review and delete the uploaded file, while also providing a visually appealing and interactive interface with animations and hover effects. This component code can be assessed at /frontend/app/components/shared/Uploaded.tsx.


Uploader Component

Uploader Component

This component provides a user interface for uploading files, specifically videos or posters, with features like drag-and-drop, file type validation, size limits, upload progress tracking, and success/error notifications, utilizing a combination of React state management, event handling, and API integration to handle the upload process.


Update the file found in /frontend/app/components/shared/uploader.tsx with the following codes.

The changes made to this component are:

  1. Upload File Functionality: The original code didn't have the actual upload file functionality implemented. It only showed a success toast notification without uploading the file. This updated code includes the uploadFile function from api.service that handles the file upload.
  2. Progress Tracking: The updated code tracks the upload progress and displays it on the UI.
  3. Error Handling: The updated code includes error handling for the file upload process.
  4. File Type Validation: The updated code uses a more robust file type validation using a regular expression.
  5. Code Organization: The updated code is better organized, with separate functions for handling different tasks, making it easier to read and maintain.
  6. UI Updates: The updated code includes some UI updates, such as showing the upload progress and a cancel button during upload.


This updated code is more complete and robust, with actual file upload functionality, progress tracking, error handling, and better code organization.


The video below explains what each component does in more detail, kindly check it out for your betterment.

And that is it guys, we have completed this project, and the last step we need to take is to launch this project on the browser. Run $ yarn build && yarn start to see the project live on the browser.


If you encounter any issues, refer to the following resources for troubleshooting. Till next time, all the best!

About Author

I am a web3 developer and the founder of Dapp Mentors, a company that helps businesses and individuals build and launch decentralized applications. I have over 8 years of experience in the software industry, and I am passionate about using blockchain technology to create new and innovative applications. I run a YouTube channel called Dapp Mentors where I share tutorials and tips on web3 development, and I regularly post articles online about the latest trends in the blockchain space.