Refactor MovieList component to support multiple movie categories with sorting and filtering options; update Home page to display categorized movie lists; enhance global styles for grid layout.
This commit is contained in:
		
							parent
							
								
									2359cfc582
								
							
						
					
					
						commit
						b08cdea130
					
				|  | @ -43,3 +43,7 @@ | ||||||
|   width: calc(--value(integer) / 0.12 * 1%); |   width: calc(--value(integer) / 0.12 * 1%); | ||||||
|   padding: 0 15px; |   padding: 0 15px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @utility grid-auto-cols-* { | ||||||
|  |   grid-template-columns: repeat(auto-fill, --value(integer)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,15 @@ export default async function Home() { | ||||||
|   return ( |   return ( | ||||||
|     <main> |     <main> | ||||||
|       <SearchMovies /> |       <SearchMovies /> | ||||||
|       <MovieList /> |       <MovieList | ||||||
|  |         heading="Upcoming" | ||||||
|  |         onlyUpcoming | ||||||
|  |         sort="releaseDate" | ||||||
|  |         sortDirection="desc" | ||||||
|  |       /> | ||||||
|  |       <MovieList heading="My Watchlist" onlyReleased showFilters /> | ||||||
|  |       <MovieList heading="Seen" onlySeen /> | ||||||
|  |       <MovieList heading="Favorites" onlyFavorites /> | ||||||
|     </main> |     </main> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,21 +1,92 @@ | ||||||
| "use client"; | "use client"; | ||||||
|  | import { FC, useState } from "react"; | ||||||
| import { MovieCard } from "@/components/atoms/MovieCard"; | import { MovieCard } from "@/components/atoms/MovieCard"; | ||||||
| import { useGlobalStore } from "@/app/store/globalStore"; | import { useGlobalStore } from "@/app/store/globalStore"; | ||||||
| 
 | 
 | ||||||
| export const MovieList = () => { | type Props = { | ||||||
|  |   heading: string; | ||||||
|  |   onlySeen?: boolean; | ||||||
|  |   onlyFavorites?: boolean; | ||||||
|  |   onlyUpcoming?: boolean; | ||||||
|  |   onlyReleased?: boolean; | ||||||
|  | 
 | ||||||
|  |   showFilters?: boolean; | ||||||
|  |   sort?: "title" | "releaseDate" | "popularity"; | ||||||
|  |   sortDirection?: "asc" | "desc"; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const MovieList: FC<Props> = ({ | ||||||
|  |   heading, | ||||||
|  |   onlyFavorites, | ||||||
|  |   onlySeen, | ||||||
|  |   onlyUpcoming, | ||||||
|  |   onlyReleased, | ||||||
|  |   showFilters = false, | ||||||
|  |   sort = "title", | ||||||
|  |   sortDirection = "asc", | ||||||
|  | }) => { | ||||||
|  |   const [filter, setFilter] = useState<"title" | "releaseDate" | "popularity">( | ||||||
|  |     sort | ||||||
|  |   ); | ||||||
|   const { movies } = useGlobalStore(); |   const { movies } = useGlobalStore(); | ||||||
| 
 | 
 | ||||||
|  |   const filteredMovies = movies.filter((movie) => { | ||||||
|  |     if (onlySeen) return movie.seen === 1; | ||||||
|  |     if (onlyFavorites) return movie.favorite === 1; | ||||||
|  |     if (onlyUpcoming) return new Date(movie.releaseDate) > new Date(); | ||||||
|  |     if (onlyReleased) return new Date(movie.releaseDate) < new Date(); | ||||||
|  |     return true; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   let sortedMovies = filteredMovies.sort((a, b) => { | ||||||
|  |     if (filter === "title") return a.title.localeCompare(b.title); | ||||||
|  |     if (filter === "releaseDate") | ||||||
|  |       return ( | ||||||
|  |         new Date(b.releaseDate).getTime() - new Date(a.releaseDate).getTime() | ||||||
|  |       ); | ||||||
|  |     if (filter === "popularity") return b.popularity - a.popularity; | ||||||
|  |     return 0; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   if (sortDirection === "desc") { | ||||||
|  |     sortedMovies = sortedMovies.reverse(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const handleSort = (sort: "title" | "releaseDate" | "popularity") => { | ||||||
|  |     setFilter(sort); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <section className="my-6"> |     <section className="my-20"> | ||||||
|       <div className="container"> |       <div className="container"> | ||||||
|         <h2 className="text-2xl font-bold">My Watchlist</h2> |         <div className="row"> | ||||||
|         {movies.length === 0 && ( |           <div className="col-12 md:col-10"> | ||||||
|  |             <h2 className="text-2xl font-bold">{heading}</h2> | ||||||
|  |           </div> | ||||||
|  |           {showFilters && ( | ||||||
|  |             <div className="col-12 md:col-2"> | ||||||
|  |               <select | ||||||
|  |                 className="bg-accent/70 text-white px-4 py-2 rounded-md w-full hover:bg-primary transition-colors cursor-pointer" | ||||||
|  |                 value={filter} | ||||||
|  |                 onChange={(e) => | ||||||
|  |                   handleSort( | ||||||
|  |                     e.target.value as "title" | "releaseDate" | "popularity" | ||||||
|  |                   ) | ||||||
|  |                 } | ||||||
|  |               > | ||||||
|  |                 <option value="title">Title</option> | ||||||
|  |                 <option value="releaseDate">Release Date</option> | ||||||
|  |                 <option value="popularity">Popularity</option> | ||||||
|  |               </select> | ||||||
|  |             </div> | ||||||
|  |           )} | ||||||
|  |         </div> | ||||||
|  |         {filteredMovies.length === 0 && ( | ||||||
|           <p className="text-text/60 text-sm">No movies found</p> |           <p className="text-text/60 text-sm">No movies found</p> | ||||||
|         )} |         )} | ||||||
|         <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mt-8"> |         {filteredMovies.length > 0 && ( | ||||||
|           {movies |           <div className="grid grid-auto-cols-282 gap-6 mt-8 justify-center"> | ||||||
|             .sort((a, b) => a.title.localeCompare(b.title)) |             {sortedMovies.map((movie) => ( | ||||||
|             .map((movie) => ( |  | ||||||
|               <MovieCard |               <MovieCard | ||||||
|                 key={movie.id} |                 key={movie.id} | ||||||
|                 {...movie} |                 {...movie} | ||||||
|  | @ -24,7 +95,8 @@ export const MovieList = () => { | ||||||
|                 favorite={movie.favorite === 1} |                 favorite={movie.favorite === 1} | ||||||
|               /> |               /> | ||||||
|             ))} |             ))} | ||||||
|         </div> |           </div> | ||||||
|  |         )} | ||||||
|       </div> |       </div> | ||||||
|     </section> |     </section> | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ export const SearchMovies = () => { | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <section className="my-6"> |     <section className="mb-20"> | ||||||
|       <div className="container"> |       <div className="container"> | ||||||
|         <div className="row justify-center"> |         <div className="row justify-center"> | ||||||
|           <div className="col-5"> |           <div className="col-5"> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue