Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/components/favorite-icon/favorite-icon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button } from "react-bootstrap";
import { useSelector, useDispatch } from "react-redux";
import { setUser } from "../../state/user/userSlice";

export const FavoriteIcon = ({ movie }) => {
export const FavoriteIcon = ({ movie, className = '' }) => {
const { user, token } = useSelector(state => state.user);

const dispatch = useDispatch();
Expand Down Expand Up @@ -33,13 +33,13 @@ export const FavoriteIcon = ({ movie }) => {
return (
<>
{isFavorite ? (
<Button variant="link" className="p-0 text-danger z-1" onClick={() => toggleMovie(user, movie, 'DELETE')}>
<Button variant="link" className={`p-0 z-1 ${className}`} onClick={() => toggleMovie(user, movie, 'DELETE')}>
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" className="bi bi-heart-fill" viewBox="0 0 16 16">
<path fillRule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314"/>
</svg>
</Button>
) : (
<Button variant="link" className="p-0 text-danger z-1" onClick={() => toggleMovie(user, movie, 'POST')}>
<Button variant="link" className={`p-0 z-1 ${className}`} onClick={() => toggleMovie(user, movie, 'POST')}>
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" className="bi bi-heart" viewBox="0 0 16 16">
<path d="m8 2.748-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143q.09.083.176.171a3 3 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15"/>
</svg>
Expand Down
40 changes: 40 additions & 0 deletions src/components/mini-movie-card/mini-movie-card.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { Link } from "react-router-dom";
import { FavoriteIcon } from "../favorite-icon/favorite-icon";
import { ToWatchIcon } from "../towatch-icon/towatch-icon";

import "./mini-movie-card.scss";

// TODO: add the movie length to the API and implement it here.
export const MiniMovieCard = ({ movie }) => {
return (
<div className="movie-information">
<div className="movie-poster">
<img
className="movie-poster__img"
src={movie.ImagePath}
/>
<div className="movie-poster__overlay z-1">
<div className="position-absolute top-0 end-0 z-2 mt-2 me-3 d-flex gap-2">
<FavoriteIcon className="text-white" movie={movie} />
<ToWatchIcon className="text-white" movie={movie} />
</div>

<div className="movie-details">
<p>
<Link to={`/movies/${encodeURIComponent(movie.id)}`} className="z-0 stretched-link">{movie.Title}</Link>
</p>
<div>
<span className="movie-details__rating">{movie.MPA}</span>
<ul className="movie-details__list">
<li>1h 56m</li>
<li>{movie.ReleaseYear}</li>
</ul>
</div>
</div>
</div>
</div>
<p className="movie-title">{movie.Title}</p>
</div>
);
};
113 changes: 113 additions & 0 deletions src/components/mini-movie-card/mini-movie-card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
.movie-information {
width: 124px;
margin-right: 12px;
transition: width 0.4s;

&:hover {
width: 258px;
}

&:hover > .movie-poster > .movie-poster__overlay {
display: flex;
align-items: end;
}

&:hover > .movie-poster > .movie-poster__overlay > .movie-details {
display: block;
opacity: 1;
}
}

.movie-poster {
height: 162px;
overflow: hidden;
transition: all 0.4s;
width: 100%;
position: relative;

&__img {
width: 100%;
display: block;
object-fit: cover;
height: 100%;
border-radius: 0.5rem;
z-index: 1;
}

&__overlay {
position: absolute;
top: 0;
z-index: 2;
background-color: rgba(0, 0, 0, 0.35);
width: 100%;
height: 100%;
border-radius: 0.5rem;
overflow: hidden;
display: none;
}
}

.movie-details {
color: #fff;
font-weight: 700;
padding: 1rem;
overflow: hidden;
font-size: 0.8rem;
display: none;
opacity: 0;
transition: all 0.4s;

p > a {
margin: 0;
font-size: 1.1rem;
text-shadow: 0 1px 2px #3c4043, 0 1px 3px #3c4043;
text-wrap: nowrap;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: white;
text-decoration: none;
letter-spacing: .2px;
}

div {
align-items: center;
display: flex;
font-size: 14px;
margin-top: 7px;
min-height: 16px;
text-shadow: 0 1px 2px #3c4043, 0 1px 3px #3c4043;
text-wrap: nowrap;
}

&__rating {
border: solid #fff 1px;
box-sizing: border-box;
font-size: 12px;
margin-right: 8px;
padding: 0 3px;
}

&__list {
display: flex;
margin: 0;
padding: 0;
list-style-type: none;

li:not(:last-child)::after {
content: "·";
margin: 0 4px;
}
}
}

.movie-title {
font-size: 14px;
color: rgb(108, 117, 125);
text-wrap: nowrap;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 0.4rem;
letter-spacing: .2px;
}
4 changes: 2 additions & 2 deletions src/components/movie-card/movie-card.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export const MovieCard = ({ movie }) => {
<Card.Img variant="top" src={movie.ImagePath} />
<Card.Body className="d-flex flex-column">
<Card.Text className="d-flex justify-content-end mb-3 gap-2">
<FavoriteIcon movie={movie} />
<ToWatchIcon movie={movie} />
<FavoriteIcon className="text-danger" movie={movie} />
<ToWatchIcon className="text-primary" movie={movie} />
</Card.Text>
<Card.Title>{movie.Title}</Card.Title>
<Card.Text>{movie.Description}</Card.Text>
Expand Down
10 changes: 5 additions & 5 deletions src/components/movie-view/movie-view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Link } from "react-router-dom";
import { FavoriteIcon } from "../favorite-icon/favorite-icon";
import { RatingIcon } from "../rating-icon/rating-icon";
import { PopularityIcon } from "../popularity-icon/popularity-icon";
import { MoviesList } from "../movies-list/movies-list";
import { MoviesSlider } from "../movies-slider/movies-slider";
import { ToWatchIcon } from "../towatch-icon/towatch-icon";
import { GenreBadge } from "../genre-badge/genre-badge";
import { DirectorLink } from "./director-link";
Expand Down Expand Up @@ -95,15 +95,15 @@ export const MovieView = () => {
<Col md={6}>
<div className="d-flex justify-content-center bg-dark rounded-3 py-3 position-relative">
<img src={movie.ImagePath} />
<div className="position-absolute top-0 end-0 text-danger m-3 d-flex gap-2">
<FavoriteIcon movie={movie} />
<ToWatchIcon movie={movie} />
<div className="position-absolute top-0 end-0 m-3 d-flex gap-2">
<FavoriteIcon className="text-danger" movie={movie} />
<ToWatchIcon className="text-primary" movie={movie} />
</div>
</div>
</Col>
</Row>

<MoviesList movies={similarMovies} title={"Similar Movies"} description={"No similar movies found!"} />
<MoviesSlider movies={similarMovies} title={"Similar Movies"} description={"No similar movies found!"} />
</>
);
};
24 changes: 0 additions & 24 deletions src/components/movies-list/movies-list.jsx

This file was deleted.

77 changes: 77 additions & 0 deletions src/components/movies-slider/movies-slider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useId, useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import { MiniMovieCard } from "../mini-movie-card/mini-movie-card";
import { SliderButtonPrev } from "./slider-button-prev";
import { SliderButtonNext } from "./slider-button-next";

import "./movies-slider.scss";

// TODO: fix the prev and next button
export const MoviesSlider = ({ movies, title, description = "Empty List" }) => {
const sliderId = useId();
const [showNext, setShowNext] = useState(false);
const [showPrev, setShowPrev] = useState(false);

function calculateNextButton() {
const sliderContainer = document.getElementById(sliderId);
const sliderContainerWidth = sliderContainer.clientWidth;
const sliderContainerMaxScroll = sliderContainer.scrollWidth - sliderContainerWidth;
setShowNext(sliderContainer.scrollLeft < sliderContainerMaxScroll);
}

function handleNextClick(event) {
event.preventDefault();
const sliderContainer = document.getElementById(sliderId);
const sliderContainerWidth = sliderContainer.clientWidth;
sliderContainer.scrollLeft = sliderContainer.scrollLeft + sliderContainerWidth;
calculateNextButton();
calculatePrevButton();
}

function calculatePrevButton() {
const sliderContainer = document.getElementById(sliderId);
setShowPrev(sliderContainer.scrollLeft > 0);
}

function handlePrevClick(event) {
event.preventDefault();
const sliderContainer = document.getElementById(sliderId);
const sliderContainerWidth = sliderContainer.clientWidth;
sliderContainer.scrollLeft -= sliderContainerWidth;
calculateNextButton();
calculatePrevButton();
}

useEffect(() => {
const sliderContainer = document.getElementById(sliderId);

if (sliderContainer) {
calculateNextButton();
calculatePrevButton();
}

});

return (
<Row>
<Col md={12}>
<h3 className="mb-4">{ title }</h3>
{movies.length !== 0 ? (
<section className="slider-wrapper">
<SliderButtonPrev show={showPrev} sliderId={sliderId} onClick={handlePrevClick} />
<SliderButtonNext show={showNext} sliderId={sliderId} onClick={handleNextClick} />
<div className="slides-container" id={sliderId}>
{movies.map(movie => (
<div className="slide" key={movie.id}>
<MiniMovieCard movie={movie} />
</div>
))}
</div>
</section>
) : (
<p>{description}</p>
)}
</Col>
</Row>
)
}
Loading