Lecture_Notes/Non-DSA Notes/FullStack-LLD/LLD-3 (React)/React-7 IMDB Part 4 (Adding Features to WatchList.md
mrinal1224 98aa698dd9 push
2024-05-07 12:57:28 +05:30

43 KiB

Agenda:

  • Add movies to the watchlist using local storage.
  • Implement a feature to sort movies by ratings and popularity.
  • Incorporate a feature to filter movies based on genre.
  • Add functionality to delete movies from the watchlist.
  • Integrate a search feature to find movies.

Setting Movies in Local Storage:

Note to instructor - Help students understand and brainstorm this feature.

We are storing favorite movies in the watchList array, and now we will save them to local storage.

Pseudocode

// watchList handlers

const addToWatchList = (movie) => {
    const newWatchList = [...watchList, movie];
    setWatchList(newWatchList);
    localStorage.setItem('imdb', JSON.stringify(newWatchList))
}

Note to instructor - Please feel free to test if everything is functioning correctly up to this point.

Next, we will retrieve the objects from local storage to display them in our watchlist. Here, we will retrieve all the items.

Pseudocode

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function WatchList() {
    const [favourites, setFavourites] = useState([]);
    
    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);
            
            axios
                .get('URL_HERE')
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);
    
    return (
        <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
            <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                <thead>  
                    <tr className="bg-gray-50">
                        <th className="px-6 py-4 font-medium text-gray-900">Name</th> 
                        <th>
                            <div className="flex">
                                <div>Ratings</div>
                            </div>
                        </th>
                        <th>
                            <div className="flex">
                                <div>Popularity</div>
                            </div>
                        </th>
                        <th>
                            <div className="flex">
                                <div>Genre</div>
                            </div>
                        </th>
                    </tr>
                </thead>
                <tbody className="divide-y divide-gray-100 border-t border-gray-100">  
                    {favourites.map((movie) => (
                        <tr className="hover:bg-gray-50" key={movie.id}>
                            <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                            </td>
                            <td className="pl-6 py-4">
                                {movie.vote_average}
                            </td>
                            <td className="pl-6 py-4">
                                {movie.popularity}
                            </td>
                            <td className="pl-2 py-4">
                                Action
                            </td>
                        </tr>
                    ))}
                </tbody>
            </table>
        </div>
    );
}

export default WatchList;


This code manages a list of favorite movies (favourites) by first checking and retrieving any saved movies from local storage. It then makes an API request to fetch additional movie data based on a specified URL when the pageNum dependency changes. The retrieved movie data is stored in the favourites state variable, and the fetched movie results are stored in the movies state variable.

Now, let's delve into the "Remove from Watchlist" functionality.

Pseudocode

// watchList handlers

const removeFromWatchList = (movie) => {
    const filteredWatchList = watchList.filter((m) => {
        return m.id !== movie.id;
    });
    setWatchList(filteredWatchList);
    localStorage.setItem('imdb', JSON.stringify(filteredWatchList));
}

This removes a movie from the watchlist by filtering out the movie with a matching ID from the watchList state. The updated watchlist is then set in the state, and the modified list is stored in local storage under the key 'imdb' after converting it to a JSON string.

We will now modify this condition. If the movie is included in our watchlist, the code will be updated as follows:

Pseudocode

<div className="p-2 bg-gray-900 rounded-xl absolute right-2 top-2">
    {watchList.includes(movie) === false ? (
        <div onClick={() => addToWatchList(movie.id)}>
            😀
        </div>
    ) : (
        <div onClick={() => removeFromWatchList(movie.id)}>
            ❌
        </div>
    )}
</div>


This change allows for proper handling of adding and removing movies from the watchlist based on their presence in the watchList array.

We have successfully retrieved all movies from the watchlist component after storing them in local storage

To achieve this, we will create a new component and wrap the entire content within this fragment. This will allow us to structure the layout further with additional div elements as needed.

Pseudocode

function WatchList() {
    let movies = {
        // Some movie data here
    }
    
    let genreIds = {
        28: "Action",
        12: "Adventure",
        // Some data here
    }

    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);
    
    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);
            
            axios
                .get(
                    // URL_HERE
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genre
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]]);
        setGenres(["All genres", ...temp]);
    });
    
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return <div>{genre}</div>
                })}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>  
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th> 
                            <th>
                                <div className="flex">
                                    <div>Ratings</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">  
                        {favourites.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.vote_average}
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.popularity}
                                </td>
                                <td className="pl-2 py-4">
                                    Action
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;

This is responsible for rendering a list of movie genres in the user interface. It first creates a div element to display the genres using the map function, and then it sets up a useEffect to populate the genres state variable. Inside the useEffect, it maps the genre IDs of movies to their corresponding genre names using the genreIds object and includes "All genres" as the first option. This enables users to filter movies by genre, and the genres are dynamically generated based on the movies in the movie array.

To update the genres, we will replace the static actions with the actual genre data.

Pseudocode

<td className="pl-2 py-4">
    Action
</td>   

Pseudocode

function WatchList() {
    let movies = {
        // some movie data here
    }

    let genreIds = {
        28: "Action",
        12: "Adventure"
        // some data here 
    }

    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);

    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);

            axios
                .get(
                    // URL here
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genres
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]]);
        setGenres(["All genres", ...temp]);
    });

    // Last class code
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return <div>{genre}</div>;
                })}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    <div>Ratings</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {favourites.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">{movie.vote_average}</td>
                                <td className="pl-6 py-4">{movie.popularity}</td>
                                <td className="pl-2 py-4">{genreIds[movie.genre_ids[0]]}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;


Now, we will proceed to add a feature that allows us to filter movies based on their genres. To implement this functionality, we will simply...

Pseudocode

function WatchList() {
    let movies = {
        // some movie data here
    }

    let genreIds = {
        28: "Action",
        12: "Adventure"
        // some data here 
    }

    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);
    const [currGenre, setCurrGenre] = useState("All Genres"); // Added current genre state

    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);

            axios
                .get(
                    // URL here
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genres
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]]);
        setGenres(["All Genres", ...temp]);
    });

    // Genre filter
    const filteredArray = currGenre === 'All Genres' ? favourites : favourites.filter((movie) => genreIds[movie.genre_ids[0]]);

    // Last class code
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return (
                        <div key={genre} onClick={() => setCurrGenre(genre)} className={currGenre === genre ? "bg-blue-200" : ""}>
                            {genre}
                        </div>
                    );
                })}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    <div>Ratings</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {filteredArray.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">{movie.vote_average}</td>
                                <td className="pl-6 py-4">{movie.popularity}</td>
                                <td className="pl-2 py-4">{genreIds[movie.genre_ids[0]]}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;


In this update, we introduced the currGenre state variable to track the currently selected genre for movie filtering. We created a section in the component that presents genres as clickable options. When a genre is selected, the currGenre state is updated accordingly.

Additionally, we introduced the filteredArray variable to facilitate movie filtering based on the chosen genre. If "All Genres" is selected, all movies from the favorites list are displayed. Otherwise, movies are filtered by their genre using the genreIds mapping.

Now, for each genre, let's generate a button.

Pseudocode

function WatchList() {
    let genreIds = {
        28: "Action",
        12: "Adventure"
        // some data here 
    }
    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);
    // state for filtering genres
    const [currGenre, setCurrGenre] = useState('All Genres')

    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb')
            moviesFromLS = JSON.parse(moviesFromLS) || []
            setWatchList(moviesFromLS)

            axios
                .get(
                    // URL here
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genre
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]])
        setGenres(["All genres", ...temp])
    });

    // creating filter func acc to genre
    let filteredArray = []

    // genre filter 
    filteredArray = currGenre == 'All Genres' ? favourites : favourites.filter((movie) => genreIds[movie.genre_ids[0]])

    // last class code 
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return (
                        <button
                            className={currGenre == genre ? 'm-2 text-lg px-2 bg-blue-400 text-white rounded-xl font-bold' : 'm-2 text-lg px-2 bg-gray-400 text-white rounded-xl font-bold'}
                        >
                            {genre}
                        </button>
                    )
                })}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    <div>Ratings</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {favourites.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">{movie.vote_average}</td>
                                <td className="pl-6 py-4">{movie.popularity}</td>
                                <td className="pl-2 py-4">{genreIds[movie.genre_ids[0]]}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;




Now, we have the ability to alter genres by setting the genre upon clicking.

Pseudocode

function WatchList() {
        
    let genreIds = {

        28: "Action",
        12: "Adventure"
        // some data here 
    }
    const[favourites, setFavourites] = useState([])
    const[genres, setGenres] = useState([])
    // state for filtering genres
    const[currGenre, setCurrGenre] = useState('All Genres')
    
    useEffect(()=>{
        (function() {
            let moviesFromLS = localStorage,getItem('imdb')
            moviesFromLS = JSON.parse(moviesFromLS) || []
            setWatchList(moviesFromLS)
            
            axios
            .get(
            )
            .then((res) =>
                 {
                setMovies(res.data.results);
            });
        })();
    }, [pageNum]);
    
    
    // useEffect for genre
      useEffect(()=>{
          let temp = movies.map((movie) =>genreIds[movie.genre_ids[0]])
          setGenres(["All genres", ...temp])
    });
    
    // creating filter func acc to genre
    
    let filteredArray = []
    
    // genre filter 
    
    filteredArray = currGenre == 'All Genres' ? favourites : favourites.filter((movie) =>genreIds[movie.genre_ids[0]])
    
    
    // last class code 
    return (
        
        <>
        <div className = "mt-6 flex space-x-2 justify-center">
            {genres.map((genre)=>{
                return <button className = {currGenre == genre ? 'm-2 text-lg px-2 bg-blue-400 text-white rounded-xl font-bold' : 'm-2 text-lg px-2 bg-gray-400 text-white rounded-xl font-bold'}
                           
                           onClick={()=>{
                     setCurrGenre(genre)   
                    }}
                           
                           
                           >{genre}</button>
            })}
        </div>
        <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
            <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                <thead>  
                    <tr className="bg-gray-50">
                        <th className="px-6 py-4 font-medium text-gray-900">Name</th> 
                        <th>
                            <div className="flex">
                                <div>Ratings</div>
                            </div>
                        </th>
                        <th>
                            <div className="flex">
                                <div>Popularity</div>
                            </div>
                        </th>
                        <th>
                            <div className="flex">
                                <div>Genre</div>
                            </div>
                        </th>
                    </tr>
                </thead>
                <tbody className="divide-y divide-gray-100 border-t border-gray-100">  
                    // updated this to filteredArray as we are making changes in this array
                    {filteredArray.map((movie) => (
                        <tr className="hover:bg-gray-50" key={movie.id}>
                            <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                            </td>
                            <td className="pl-6 py-4">
                                {movie.vote_average}
                            </td>
                            <td className="pl-6 py-4">
                                {movie.popularity}
                            </td>
                            <td className="pl-2 py-4">
                               {genreIds[movie.genre_ids[0]]}
                            </td>
                        </tr>
                    ))}
                </tbody>
            </table>
        </div>
        </>
    );
}

export default WatchList;

To understand sorting, think of it as arranging data in a specific order, which can be either ascending or descending. We will use JavaScript's sort method to achieve this.

First, we'll create a state variable to manage the sorting.

Pseudocode

function WatchList() {
    let genreIds = {
        28: "Action",
        12: "Adventure"
        // some data here 
    }
    const [favourites, setFavourites] = useState([])
    const [genres, setGenres] = useState([])
    // state for filtering genres
    const [currGenre, setCurrGenre] = useState('All Genres')
    // state for sorting by rating 
    const [rating, setRating] = useState(0)

    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb')
            moviesFromLS = JSON.parse(moviesFromLS) || []
            setWatchList(moviesFromLS)

            axios
                .get(
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genre
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]])
        setGenres(["All genres", ...temp])
    });

    // creating filter func acc to genre
    let filteredArray = []

    // genre filter 
    filteredArray = currGenre === 'All Genres' ? favourites : favourites.filter((movie) => genreIds[movie.genre_ids[0]])

    // condition for sorting of movies with respect to ratings
    if (rating === -1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objB.vote_average - objA.vote_average
        })
    }

    if (rating === 1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objA.vote_average - objB.vote_average
        })
    }

    // last class code 
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return <button className={currGenre === genre ? 'm-2 text-lg px-2 bg-blue-400 text-white rounded-xl font-bold' : 'm-2 text-lg px-2 bg-gray-400 text-white rounded-xl font-bold'}
                        onClick={() => {
                            setCurrGenre(genre)
                        }}>{genre}</button>
                })}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    {/* image showing arrow for up rating */}
                                    <img src=""
                                        onClick={() => {
                                            setRating(1)
                                        }}
                                    />
                                    <div>Ratings</div>
                                    {/* image showing arrow for down rating */}
                                    <img src=""
                                        onClick={() => {
                                            setRating(-1)
                                        }}
                                    />
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {/* updated this to filteredArray as we are making changes in this array */}
                        {filteredArray.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.vote_average}
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.popularity}
                                </td>
                                <td className="pl-2 py-4">
                                    {genreIds[movie.genre_ids[0]]}
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;

The provided code segment handles the sorting of movies based on ratings. It uses a rating state variable to determine the sorting order. If rating is set to -1, it sorts the filteredArray of movies in descending order of ratings (highest to lowest). If rating is set to 1, it sorts the filteredArray in ascending order of ratings (lowest to highest). This functionality allows users to toggle between sorting movies by ratings in both ascending and descending orders.

Now, moving forward to implement the delete functionality.

Pseudocode

function WatchList() {
    const genreIds = {
        28: "Action",
        12: "Adventure"
        // some data here 
    };

    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);
    // state for filtering genres
    const [currGenre, setCurrGenre] = useState('All Genres');
    // state for sorting by rating 
    const [rating, setRating] = useState(0);

    useEffect(() => {
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);

            axios
                .get(
                    // URL here
                )
                .then((res) => {
                    setMovies(res.data.results);
                });
        })();
    }, [pageNum]);

    // useEffect for genre
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]]);
        setGenres(["All genres", ...temp]);
    });

    // creating filter func acc to genre
    let filteredArray = [];

    // genre filter 
    filteredArray = currGenre === 'All Genres' ? favourites : favourites.filter((movie) => genreIds[movie.genre_ids[0]]);

    // condition for sorting movies according to rating
    if (rating === -1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objB.vote_average - objA.vote_average;
        });
    }

    if (rating === 1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objA.vote_average - objB.vote_average;
        });
    }

    // delete functionality
    const del = (movie) => {
        let newArray = favourites.filter((m) => m.id !== movie.id);
        setFavourites([...newArray]);
        localStorage.setItem('imdb', JSON.stringify(newArray));
    };

    // last class code 
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => (
                    <button className={currGenre === genre ? 'm-2 text-lg px-2 bg-blue-400 text-white rounded-xl font-bold' : 'm-2 text-lg px-2 bg-gray-400 text-white rounded-xl font-bold'}
                        onClick={() => {
                            setCurrGenre(genre);
                        }}>
                        {genre}
                    </button>
                ))}
            </div>
            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    {/* image showing arrow for up rating */}
                                    <img
                                        src=""
                                        onClick={() => {
                                            setRating(1);
                                        }}
                                    />
                                    <div>Ratings</div>
                                    {/* image showing arrow for down rating */}
                                    <img
                                        src=""
                                        onClick={() => {
                                            setRating(-1);
                                        }}
                                    />
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {/* updated this to filteredArray as we are making changes in this array */}
                        {filteredArray.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">{movie.vote_average}</td>
                                <td className="pl-6 py-4">{movie.popularity}</td>
                                <td className="pl-2 py-4">{genreIds[movie.genre_ids[0]]}</td>
                                {/* adding delete button */}
                                <td className="pl-2 py-4">
                                    <button className="text-red-600" onClick={() => del(movie)}>Delete</button>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;


The code now includes a delete functionality that allows you to remove movies from the watchlist. The del function filters the movies and updates the state and local storage accordingly.

Pseudocode

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function WatchList() {
    // Define genre IDs
    let genreIds = {
        28: "Action",
        12: "Adventure"
        // Add more genre data here
    }

    // State for favorites, genres, selected genre, rating, and search string
    const [favourites, setFavourites] = useState([]);
    const [genres, setGenres] = useState([]);
    const [currGenre, setCurrGenre] = useState('All Genres');
    const [rating, setRating] = useState(0);
    const [searchStr, setSearchStr] = useState('');

    useEffect(() => {
        // Fetch movie data from local storage and API
        (function () {
            let moviesFromLS = localStorage.getItem('imdb');
            moviesFromLS = JSON.parse(moviesFromLS) || [];
            setFavourites(moviesFromLS);

            axios.get(
                // Add API URL here
            ).then((res) => {
                setMovies(res.data.results);
            });
        })();
    }, [pageNum]);

    // useEffect for genre
    useEffect(() => {
        let temp = movies.map((movie) => genreIds[movie.genre_ids[0]]);
        setGenres(["All genres", ...temp]);
    });

    // Create filter function according to genre
    let filteredArray = [];

    // Genre filter
    filteredArray = currGenre === 'All Genres' ? favourites : favourites.filter((movie) => genreIds[movie.genre_ids[0]]);

    // Condition for sorting movies according to rating
    if (rating === -1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objB.vote_average - objA.vote_average;
        });
    }

    if (rating === 1) {
        filteredArray = filteredArray.sort(function (objA, objB) {
            return objA.vote_average - objB.vote_average;
        });
    }

    // Movies searching functionality
    filteredArray = filteredArray.filter((movie) => {
        return movie.title.toLowerCase().includes(searchStr.toLowerCase());
    });

    // Delete functionality
    const del = (movie) => {
        let newArray = favourites.filter((m) => m.id !== movie.id);
        setFavourites([...newArray]);
        localStorage.setItem('imdb', JSON.stringify(newArray));
    }

    // Return the JSX for the WatchList component
    return (
        <>
            <div className="mt-6 flex space-x-2 justify-center">
                {genres.map((genre) => {
                    return (
                        <button
                            key={genre}
                            className={currGenre === genre ? 'm-2 text-lg px-2 bg-blue-400 text-white rounded-xl font-bold' : 'm-2 text-lg px-2 bg-gray-400 text-white rounded-xl font-bold'}
                            onClick={() => {
                                setCurrGenre(genre);
                            }}
                        >
                            {genre}
                        </button>
                    );
                })}
            </div>

            {/* Input field for movie search */}
            <div className="text-center">
                <input
                    type="text"
                    className="border bg-gray-200 border-4 text-center p-1 m-2"
                    placeholder="Search For Movies"
                    value={searchStr}
                    onChange={(e) => setSearchStr(e.target.value)}
                />
            </div>

            <div className="overflow-hidden rounded-lg border border-gray-200 shadow-md m-5">
                <table className="w-full border-collapse bg-white text-left text-sm text-gray-500">
                    <thead>
                        <tr className="bg-gray-50">
                            <th className="px-6 py-4 font-medium text-gray-900">Name</th>
                            <th>
                                <div className="flex">
                                    {/* Image showing arrow for up rating */}
                                    <img
                                        src=""
                                        onClick={() => {
                                            setRating(1);
                                        }}
                                    />
                                    <div>Ratings</div>
                                    {/* Image showing arrow for down rating */}
                                    <img
                                        src=""
                                        onClick={() => {
                                            setRating(-1);
                                        }}
                                    />
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Popularity</div>
                                </div>
                            </th>
                            <th>
                                <div className="flex">
                                    <div>Genre</div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-gray-100 border-t border-gray-100">
                        {filteredArray.map((movie) => (
                            <tr className="hover:bg-gray-50" key={movie.id}>
                                <td className="flex items-center px-6 py-4 font-normal text-gray-900">
                                    <img className="h-[6rem] w-[10rem] object-fit" src="" alt="" />
                                    <div className="font-medium text-gray-700 text-sm">{movie.title}</div>
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.vote_average}
                                </td>
                                <td className="pl-6 py-4">
                                    {movie.popularity}
                                </td>
                                <td className="pl-2 py-4">
                                    {genreIds[movie.genre_ids[0]]}
                                </td>
                                {/* Adding delete button */}
                                <td className="pl-2 py-4">
                                    <button className="text-red-600" onClick={() => del(movie)}>Delete</button>
                                </td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        </>
    );
}

export default WatchList;

A new state variable, searchStr, is introduced using useState to hold the user's search string. The movie searching functionality is implemented by further filtering the filteredArray based on searchStr. It utilizes the filter method to match the lowercase movie titles with the lowercase search string, effectively enabling movie searches. An input field is added to the component, allowing users to input their search query, with the value bound to searchStr and an onChange handler to update it based on user input.