feat: enhance MovieList and MovieRow components with display type toggle and additional props for improved flexibility

This commit is contained in:
Norbert Maciaszek 2025-08-21 21:55:59 +02:00
parent 6bd1b289d7
commit 653380f0fb
5 changed files with 67 additions and 22 deletions

View File

@ -47,6 +47,8 @@ export default async function Home() {
loadMore
icon={<FaPlay />}
colors="blue"
showFilters={false}
displayType="list"
/>
</section>
@ -57,6 +59,8 @@ export default async function Home() {
loadMore
icon={<FaCalendar />}
colors="blue"
showFilters={false}
displayType="list"
/>
</section>
@ -67,6 +71,8 @@ export default async function Home() {
loadMore
icon={<FaFire />}
colors="red"
showFilters={false}
displayType="list"
/>
</section>
@ -77,6 +83,8 @@ export default async function Home() {
loadMore
icon={<FaChartLine />}
colors="green"
showFilters={false}
displayType="list"
/>
</section>

View File

@ -1,6 +1,6 @@
"use client";
import { useOutsideClick } from "@/hooks/useOutsideClick";
import { FC, useEffect, useRef, useState } from "react";
import { FC, ReactNode, useEffect, useRef, useState } from "react";
import { FaFilter } from "react-icons/fa";
import { Button } from "../Button";
@ -9,11 +9,17 @@ type Props = {
label: string;
value: string;
}[];
icon?: ReactNode;
defaultValue: string;
callback?: (value: string) => void;
};
export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => {
export const Dropdown: FC<Props> = ({
items,
icon,
defaultValue,
callback,
}) => {
const ref = useRef<HTMLDivElement>(null);
const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState<string>(defaultValue);
@ -27,7 +33,7 @@ export const Dropdown: FC<Props> = ({ items, defaultValue, callback }) => {
return (
<div ref={ref} className="relative inline-block">
<Button theme="glass" size="icon" onClick={() => setIsOpen(!isOpen)}>
<FaFilter />
{icon || <FaFilter />}
</Button>
<div

View File

@ -4,9 +4,16 @@ import Link from "next/link";
import { FC } from "react";
import { FaCalendar, FaClock, FaStar } from "react-icons/fa";
export const MovieRow: FC<{ movie: Movie; isUpcoming: boolean }> = ({
type Props = {
movie: Movie;
isUpcoming?: boolean;
compact?: boolean;
};
export const MovieRow: FC<Props> = ({
movie,
isUpcoming,
isUpcoming = false,
compact = false,
}) => {
const daysSinceRelease = Math.abs(
Math.floor(
@ -56,17 +63,19 @@ export const MovieRow: FC<{ movie: Movie; isUpcoming: boolean }> = ({
</div>
</div>
<div
className={`text-xs px-2 py-1 rounded-full font-medium ${
isUpcoming
? "bg-blue-500/20 text-blue-400"
: "bg-green-500/20 text-green-400"
}`}
>
{isUpcoming
? `za ${daysSinceRelease} dni`
: `od ${daysSinceRelease} dni`}
</div>
{!compact && (
<div
className={`text-xs px-2 py-1 rounded-full font-medium ${
isUpcoming
? "bg-blue-500/20 text-blue-400"
: "bg-green-500/20 text-green-400"
}`}
>
{isUpcoming
? `za ${daysSinceRelease} dni`
: `od ${daysSinceRelease} dni`}
</div>
)}
</Link>
);
};

View File

@ -71,7 +71,7 @@ export const MovieCast: FC<Props> = ({ movieDetails }) => {
{limit < movieDetails.credits.cast.length && (
<div className="flex justify-center">
<Button
theme="teal"
theme="glass"
size="small"
className="mt-6"
onClick={() => {

View File

@ -7,11 +7,14 @@ import { Dropdown } from "@/components/atoms/Dropdown";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { Button } from "@/components/atoms/Button";
import { Label } from "@/components/atoms/Label";
import { FaList } from "react-icons/fa";
import { MovieRow } from "@/components/atoms/MovieRow";
type Props = {
heading?: string;
icon?: ReactNode;
colors?: keyof typeof colorsMap;
displayType?: "grid" | "list";
overrideMovies?: Movie[];
@ -44,10 +47,12 @@ export const MovieList: FC<Props> = ({
sort: sortType = "releaseDate",
sortDirection = "asc",
loadMore = false,
displayType = "grid",
}) => {
const { movies: storeMovies } = useGlobalStore();
const movies = overrideMovies || storeMovies;
const [display, setDisplay] = useState<"grid" | "list">(displayType);
const [filter, setFilter] = useState({
seen: filterSeenInitial,
favorites: filterFavoritesInitial,
@ -58,7 +63,7 @@ export const MovieList: FC<Props> = ({
sortType
);
const [loaded, setLoaded] = useState(loadMore ? 4 : movies.length);
const [loaded, setLoaded] = useState(loadMore ? 8 : movies.length);
const [parent] = useAutoAnimate();
const filteredMovies = movies.filter((movie) => {
@ -189,6 +194,15 @@ export const MovieList: FC<Props> = ({
defaultValue={sort}
callback={(value) => setSort(value as "title")}
/>
<Button
theme="glass"
size="icon"
onClick={() =>
setDisplay(display === "grid" ? "list" : "grid")
}
>
<FaList />
</Button>
</div>
)}
</div>
@ -201,14 +215,22 @@ export const MovieList: FC<Props> = ({
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-y-6 gap-3 sm:gap-6 mt-8 justify-center"
ref={parent}
>
{sortedMovies.map((movie) => (
<MovieCard key={movie.id} layout="aurora" {...movie} />
))}
{sortedMovies.map((movie) =>
display === "grid" ? (
<MovieCard key={movie.id} layout="aurora" {...movie} />
) : (
<MovieRow key={movie.id} movie={movie} compact />
)
)}
</div>
)}
{loadMore && filteredMovies.length > loaded && (
<div className="flex justify-center mt-10">
<Button theme="teal" onClick={() => setLoaded(movies.length)}>
<Button
size="small"
theme="glass"
onClick={() => setLoaded(movies.length)}
>
Pokaż więcej
</Button>
</div>