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