Enhance movie management features by adding MovieList component to display user's watchlist; update MovieCard to include add/remove functionality for watchlist; refactor SearchMovies layout for improved structure; adjust global styles for primary color.
This commit is contained in:
parent
08d766bf8c
commit
2359cfc582
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--color-background: #0e1428;
|
--color-background: #0e1428;
|
||||||
--color-primary: #d95d39;
|
--color-primary: #c73b6f;
|
||||||
--color-accent: #7b9e89;
|
--color-accent: #7b9e89;
|
||||||
--color-text: #eaeaea;
|
--color-text: #eaeaea;
|
||||||
--color-textSecondary: #aaaaaa;
|
--color-textSecondary: #aaaaaa;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
import { MovieList } from "@/components/molecules/MovieList";
|
||||||
import { SearchMovies } from "@/components/molecules/SearchMovies";
|
import { SearchMovies } from "@/components/molecules/SearchMovies";
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<SearchMovies />
|
<SearchMovies />
|
||||||
|
<MovieList />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,65 @@
|
||||||
import { FC } from "react";
|
"use client";
|
||||||
|
import { FC, useState } from "react";
|
||||||
import { ReadMore } from "../ReadMore";
|
import { ReadMore } from "../ReadMore";
|
||||||
|
import { addMovie, deleteMovie } from "@/lib/db";
|
||||||
|
import { useGlobalStore } from "@/app/store/globalStore";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
overview: string;
|
overview: string;
|
||||||
releaseDate: string;
|
releaseDate: string;
|
||||||
popularity: number;
|
popularity: number;
|
||||||
imagePath: string;
|
imagePath: string;
|
||||||
|
seen: boolean;
|
||||||
|
favorite: boolean;
|
||||||
|
notes?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieCard: FC<Props> = ({
|
export const MovieCard: FC<Props> = ({
|
||||||
|
id,
|
||||||
title,
|
title,
|
||||||
releaseDate,
|
releaseDate,
|
||||||
popularity,
|
popularity,
|
||||||
overview,
|
overview,
|
||||||
imagePath,
|
imagePath,
|
||||||
|
seen,
|
||||||
|
favorite,
|
||||||
|
notes,
|
||||||
}) => {
|
}) => {
|
||||||
|
const {
|
||||||
|
movies,
|
||||||
|
addMovie: addMovieToStore,
|
||||||
|
deleteMovie: deleteMovieFromStore,
|
||||||
|
} = useGlobalStore();
|
||||||
|
const alreadyInStore = movies.find((m) => m.id === id);
|
||||||
|
|
||||||
|
const handleAdd = async () => {
|
||||||
|
const movie = {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
overview,
|
||||||
|
popularity,
|
||||||
|
releaseDate,
|
||||||
|
posterPath: imagePath,
|
||||||
|
seen: 0,
|
||||||
|
favorite: 0,
|
||||||
|
notes: "",
|
||||||
|
};
|
||||||
|
await addMovie(movie);
|
||||||
|
addMovieToStore(movie);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemove = async () => {
|
||||||
|
await deleteMovie(id);
|
||||||
|
deleteMovieFromStore(id);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full shadow-md rounded-lg overflow-hidden mx-auto">
|
<div className="flex w-full shadow-md rounded-lg overflow-hidden mx-auto group/card">
|
||||||
<div className="overflow-hidden rounded-xl relative movie-item text-white movie-card">
|
<div className="overflow-hidden rounded-xl relative movie-item text-white movie-card">
|
||||||
<div className="absolute inset-0 z-10 bg-gradient-to-t from-black via-gray-900 to-transparent"></div>
|
<div className="absolute inset-0 z-10 bg-gradient-to-t from-black via-gray-900 to-transparent"></div>
|
||||||
<div className="relative cursor-pointer group z-10 p-6 space-y-6 h-full">
|
<div className="relative group z-10 p-6 space-y-6 h-full">
|
||||||
<div className="align-self-end w-full h-full flex flex-col">
|
<div className="align-self-end w-full h-full flex flex-col">
|
||||||
<div className="h-64"></div>
|
<div className="h-64"></div>
|
||||||
<div className="flex flex-col space-y-2 inner mb-4">
|
<div className="flex flex-col space-y-2 inner mb-4">
|
||||||
|
|
@ -35,17 +74,35 @@ export const MovieCard: FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between mt-auto">
|
<div className="flex flex-row justify-between mt-auto">
|
||||||
<div className="flex flex-col datos_col">
|
<div className="flex flex-col">
|
||||||
<div className="text-sm text-gray-400">Popularity:</div>
|
<div className="text-sm text-gray-400">Popularity:</div>
|
||||||
<div className="popularity">{popularity}</div>
|
<div className="popularity">{popularity}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col datos_col">
|
<div className="flex flex-col">
|
||||||
<div className="text-sm text-gray-400">Release date:</div>
|
<div className="text-sm text-gray-400">Release date:</div>
|
||||||
<div className="release">{releaseDate}</div>
|
<div className="release">{releaseDate}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="absolute top-0 z-10 bg-transparent inset-x-0 group-hover/card:bg-white/50 transition-all opacity-0 group-hover/card:opacity-100 flex justify-center">
|
||||||
|
{!alreadyInStore && (
|
||||||
|
<button
|
||||||
|
className="bg-primary/70 text-white px-4 py-2 rounded-md w-full hover:bg-primary transition-colors cursor-pointer"
|
||||||
|
onClick={handleAdd}
|
||||||
|
>
|
||||||
|
Add to watchlist
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{alreadyInStore && (
|
||||||
|
<button
|
||||||
|
className="bg-primary/70 text-white px-4 py-2 rounded-md w-full hover:bg-primary transition-colors cursor-pointer"
|
||||||
|
onClick={handleRemove}
|
||||||
|
>
|
||||||
|
Remove from watchlist
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<figure className="absolute inset-0 w-full bottom-[20%]">
|
<figure className="absolute inset-0 w-full bottom-[20%]">
|
||||||
<img
|
<img
|
||||||
className="w-full h-96 object-cover"
|
className="w-full h-96 object-cover"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
"use client";
|
||||||
|
import { MovieCard } from "@/components/atoms/MovieCard";
|
||||||
|
import { useGlobalStore } from "@/app/store/globalStore";
|
||||||
|
|
||||||
|
export const MovieList = () => {
|
||||||
|
const { movies } = useGlobalStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="my-6">
|
||||||
|
<div className="container">
|
||||||
|
<h2 className="text-2xl font-bold">My Watchlist</h2>
|
||||||
|
{movies.length === 0 && (
|
||||||
|
<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">
|
||||||
|
{movies
|
||||||
|
.sort((a, b) => a.title.localeCompare(b.title))
|
||||||
|
.map((movie) => (
|
||||||
|
<MovieCard
|
||||||
|
key={movie.id}
|
||||||
|
{...movie}
|
||||||
|
imagePath={movie.posterPath || ""}
|
||||||
|
seen={movie.seen === 1}
|
||||||
|
favorite={movie.favorite === 1}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -14,24 +14,29 @@ export const SearchMovies = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<section className="my-6">
|
||||||
<div className="row justify-center">
|
<div className="container">
|
||||||
<div className="col-5">
|
<div className="row justify-center">
|
||||||
<SearchInput onChange={handleSearch} />
|
<div className="col-5">
|
||||||
|
<SearchInput onChange={handleSearch} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mt-8">
|
||||||
|
{results.map((result) => (
|
||||||
|
<MovieCard
|
||||||
|
key={result.id}
|
||||||
|
id={result.id}
|
||||||
|
title={result.title}
|
||||||
|
releaseDate={result.release_date}
|
||||||
|
popularity={result.popularity}
|
||||||
|
overview={result.overview}
|
||||||
|
imagePath={result.poster_path}
|
||||||
|
seen={false}
|
||||||
|
favorite={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mt-8">
|
</section>
|
||||||
{results.map((result) => (
|
|
||||||
<MovieCard
|
|
||||||
key={result.id}
|
|
||||||
title={result.title}
|
|
||||||
releaseDate={result.release_date}
|
|
||||||
popularity={result.popularity}
|
|
||||||
overview={result.overview}
|
|
||||||
imagePath={result.poster_path}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue