diff --git a/README.md b/README.md index 1186f3b..dc1aba1 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ _Video demo._ - Development: [https://dev.cinejump.lucasgabriel.com.br/](https://dev.cinejump.lucasgabriel.com.br/) - Storybook: [https://storybook.cinejump.lucasgabriel.com.br/](https://storybook.cinejump.lucasgabriel.com.br/) +> +- Figma Layout: [https://www.figma.com/file/um4dcEJCOlEvB6kCe9KCOD](https://www.figma.com/file/um4dcEJCOlEvB6kCe9KCOD) +- Figma Prototype: [https://www.figma.com/proto/um4dcEJCOlEvB6kCe9KCOD/Cinejump?node-id=7185%3A17&scaling=scale-down-width](https://www.figma.com/proto/um4dcEJCOlEvB6kCe9KCOD/Cinejump?node-id=7185%3A17&scaling=scale-down-width) + diff --git a/package.json b/package.json index 7aaaf5e..4205f8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "cinejump", "version": "1.2.0", + "devVersion": "1.3.0", "private": true, "dependencies": { "@storybook/react": "^6.0.21", diff --git a/src/components/EnvironmentLabel/index.tsx b/src/components/EnvironmentLabel/index.tsx index 2fc7741..6bb6c7f 100644 --- a/src/components/EnvironmentLabel/index.tsx +++ b/src/components/EnvironmentLabel/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { version } from '../../../package.json'; +import { devVersion } from '../../../package.json'; import { Container } from './styles'; const EnvironmentLabel: React.FC = () => { @@ -8,7 +8,9 @@ const EnvironmentLabel: React.FC = () => { return null; } - return Versão: {version} | Ambiente: Desenvolvimento; + return ( + Versão: {devVersion} | Ambiente: Desenvolvimento + ); }; export default EnvironmentLabel; diff --git a/src/components/Movie/dtos/ContainerProps.ts b/src/components/Movie/dtos/ContainerProps.ts new file mode 100644 index 0000000..a543f27 --- /dev/null +++ b/src/components/Movie/dtos/ContainerProps.ts @@ -0,0 +1,3 @@ +export default interface ContainerProps { + large?: boolean; +} diff --git a/src/components/Movie/dtos/index.ts b/src/components/Movie/dtos/index.ts index 3d26983..b0f10d2 100644 --- a/src/components/Movie/dtos/index.ts +++ b/src/components/Movie/dtos/index.ts @@ -1,4 +1,6 @@ -export default interface MovieProps { +import ContainerProps from './ContainerProps'; + +export default interface MovieProps extends ContainerProps { id: number; favorite: boolean; poster?: string; diff --git a/src/components/Movie/index.tsx b/src/components/Movie/index.tsx index 58837cf..7211598 100644 --- a/src/components/Movie/index.tsx +++ b/src/components/Movie/index.tsx @@ -10,7 +10,7 @@ import { Container, IconButton, Poster } from './styles'; import Props from './dtos'; -const Movie: React.FC = ({ ...movie }) => { +const Movie: React.FC = ({ large = false, ...movie }) => { const history = useHistory(); const { user } = useAuth(); const { favoriteList = [], UpdateFavorite } = useFavorite(); @@ -49,7 +49,7 @@ const Movie: React.FC = ({ ...movie }) => { } return ( - + diff --git a/src/components/Movie/styles.ts b/src/components/Movie/styles.ts index 83f831d..caa7605 100644 --- a/src/components/Movie/styles.ts +++ b/src/components/Movie/styles.ts @@ -1,13 +1,16 @@ import styled from 'styled-components'; -import { PosterHeight, PosterWidth, Size } from 'shared/enums'; -export const Container = styled.div` +import { Color, PosterHeight, PosterWidth, Size } from 'shared/enums'; +import ContainerProps from './dtos/ContainerProps'; + +export const Container = styled.div` position: relative; - width: ${PosterWidth.Default}; - height: ${PosterHeight.Default}; + width: ${props => (props.large ? PosterWidth.Large : PosterWidth.Default)}; + height: ${props => (props.large ? PosterHeight.Large : PosterHeight.Default)}; border-radius: ${Size.Smallest}; overflow: hidden; + border: ${props => (props.large ? 0 : `1px solid ${Color.FillSecondary}`)}; display: flex; align-items: center; justify-content: center; diff --git a/src/components/Person/dtos/ContainerProps.ts b/src/components/Person/dtos/ContainerProps.ts new file mode 100644 index 0000000..a543f27 --- /dev/null +++ b/src/components/Person/dtos/ContainerProps.ts @@ -0,0 +1,3 @@ +export default interface ContainerProps { + large?: boolean; +} diff --git a/src/components/Person/dtos/index.ts b/src/components/Person/dtos/index.ts new file mode 100644 index 0000000..7c57e1d --- /dev/null +++ b/src/components/Person/dtos/index.ts @@ -0,0 +1,8 @@ +import ContainerProps from './ContainerProps'; + +export default interface PersonProps extends ContainerProps { + id: number; + profile: string; + name: string; + character: string; +} diff --git a/src/components/Person/index.tsx b/src/components/Person/index.tsx new file mode 100644 index 0000000..aaf0c7d --- /dev/null +++ b/src/components/Person/index.tsx @@ -0,0 +1,33 @@ +import React, { useCallback } from 'react'; +import { useHistory } from 'react-router-dom'; + +import Route from 'routes/enums'; +import { + Container, + Profile, + NameContainer, + PersonName, + CharacterName, +} from './styles'; + +import Props from './dtos'; + +const Person: React.FC = ({ large = false, ...person }) => { + const history = useHistory(); + + const handleRedirect = useCallback(() => { + history.push(`${Route.PERSON}/${person.id}`); + }, [history, person.id]); + + return ( + + + + {person.name} + {person.character} + + + ); +}; + +export default Person; diff --git a/src/components/Person/styles.ts b/src/components/Person/styles.ts new file mode 100644 index 0000000..b34c50c --- /dev/null +++ b/src/components/Person/styles.ts @@ -0,0 +1,61 @@ +import styled from 'styled-components'; + +import { Color, PosterHeight, PosterWidth, Size } from 'shared/enums'; +import ContainerProps from './dtos/ContainerProps'; + +export const Container = styled.div` + position: relative; + width: ${props => (props.large ? PosterWidth.Large : PosterWidth.Default)}; + height: ${props => (props.large ? PosterHeight.Large : PosterHeight.Default)}; + border-radius: ${Size.Smallest}; + overflow: hidden; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.5); + + display: flex; + align-items: center; + justify-content: center; + + &:hover { + cursor: pointer; + + img { + width: 110%; + height: 110%; + } + } +`; + +export const Profile = styled.img` + margin-top: -5rem; + width: 100%; + height: 100%; + object-fit: cover; + transition: width 0.2s, height 0.2s; +`; + +export const NameContainer = styled.div` + position: absolute; + bottom: 0; + height: 7.4rem; + width: 100%; + background: ${Color.Fill}; + overflow: hidden; + padding: ${Size.Smallest}; +`; + +export const PersonName = styled.div` + font-size: ${Size.Small}; + color: ${Color.Secondary}; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; + +export const CharacterName = styled.div` + font-size: ${Size.Small}; + color: ${Color.Text}; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +`; diff --git a/src/components/index.ts b/src/components/index.ts index 4be78bd..b5236b6 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,6 +1,9 @@ +export { ColumnLayout, RowLayout, Wrapper, Container } from 'components/Layout'; + export { default as Button } from './Button'; export { default as EnvironmentLabel } from './EnvironmentLabel'; export { default as Input } from './Input'; export { default as Movie } from './Movie'; export { default as MovieHighlight } from './MovieHighlight'; +export { default as Person } from './Person'; export { default as Tooltip } from './Tooltip'; diff --git a/src/containers/PersonList/dtos/index.ts b/src/containers/PersonList/dtos/index.ts new file mode 100644 index 0000000..62323c6 --- /dev/null +++ b/src/containers/PersonList/dtos/index.ts @@ -0,0 +1,10 @@ +import DefaultProps from 'shared/dtos'; +import { Color } from 'shared/enums'; + +export default interface Props extends DefaultProps { + title?: string; + data: any[]; + isLoading?: boolean; + loaderColor?: Color; + message?: string; +} diff --git a/src/containers/PersonList/index.tsx b/src/containers/PersonList/index.tsx new file mode 100644 index 0000000..33fa697 --- /dev/null +++ b/src/containers/PersonList/index.tsx @@ -0,0 +1,61 @@ +import React from 'react'; + +import { ReactComponent as Loading } from 'assets/loading.svg'; + +import { Wrapper } from 'components/Layout'; +import Person from 'components/Person'; +import { + Container, + Title, + LoadingContainer, + ListContainer, + ListContent, + MessageContainer, +} from './styles'; + +import Props from './dtos'; + +const PersonList: React.FC = ({ + theme, + background, + color, + title, + data, + isLoading = false, + loaderColor, + message = 'Não há resultados.', +}) => { + return ( + + + {title && ( + + {title} + + )} + + {isLoading && ( + + + + )} + + {!isLoading && data.length > 0 && ( + + + {data.map(person => ( + + ))} + + + )} + + {!isLoading && data.length === 0 && ( + {message} + )} + + + ); +}; + +export default PersonList; diff --git a/src/containers/PersonList/styles.ts b/src/containers/PersonList/styles.ts new file mode 100644 index 0000000..98b8426 --- /dev/null +++ b/src/containers/PersonList/styles.ts @@ -0,0 +1,96 @@ +import styled from 'styled-components'; + +import DefaultProps from 'shared/dtos'; +import { Container as DefaultContainer } from 'components/Layout'; +import { Color, PosterHeight, Size } from 'shared/enums'; +import { getColor } from 'shared/utils'; + +interface LoadingProps { + loaderColor?: string; +} + +export const Container = styled(DefaultContainer)` + padding: ${Size.Medium} 0; + display: flex; + flex-direction: column; +`; + +export const Title = styled.h2` + margin-bottom: ${Size.Small}; + color: ${props => getColor(props.theme, props.color)}; + + @media (max-width: 1280px) { + margin-left: ${Size.Medium}; + } +`; + +export const LoadingContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + height: calc(${PosterHeight.Default}); + + svg { + height: ${Size.Largest}; + width: ${Size.Largest}; + fill: ${props => getColor(props.theme, props.loaderColor)}; + } +`; + +export const ListContainer = styled.div` + height: calc(${PosterHeight.Default} + 5px); + overflow-y: hidden; + overflow-x: auto; + + scroll-snap-type: x mandatory; + -webkit-overflow-scrolling: touch; + scroll-behavior: smooth; + + -ms-overflow-style: none; + scrollbar-width: 10px; + &::-webkit-scrollbar { + /* visibility: visible; */ + display: none; + } +`; + +export const ListContent = styled.div` + display: inline-flex; + padding: 0 2px; + + @media (max-width: 1280px) { + margin-left: ${Size.Medium}; + margin-right: ${Size.Smallest}; + } + + & > div { + flex: 1 0 auto; + scroll-snap-align: start; + scroll-margin-left: ${Size.Large}; + margin-right: ${Size.Medium}; + + @media (max-width: 1280px) { + scroll-margin-left: ${Size.Medium}; + margin-right: ${Size.Smallest}; + } + } + + & > div:last-child { + margin-right: 0; + + @media (max-width: 1280px) { + margin-right: ${Size.Default}; + } + } +`; + +export const MessageContainer = styled.div` + display: flex; + align-items: center; + height: calc(${PosterHeight.Default} / 3); + color: ${Color.Text}; + + @media (max-width: 1280px) { + margin-left: ${Size.Medium}; + } +`; diff --git a/src/containers/index.ts b/src/containers/index.ts index a1a2bae..d40e035 100644 --- a/src/containers/index.ts +++ b/src/containers/index.ts @@ -2,3 +2,4 @@ export { default as Footer } from './Footer'; export { default as Header } from './Header'; export { default as Highlights } from './Highlights'; export { default as MovieList } from './MovieList'; +export { default as PersonList } from './PersonList'; diff --git a/src/domains/Movie/api/Credits/RawResponse.ts b/src/domains/Movie/api/Credits/RawResponse.ts new file mode 100644 index 0000000..f68b078 --- /dev/null +++ b/src/domains/Movie/api/Credits/RawResponse.ts @@ -0,0 +1,25 @@ +export default interface RawResponse { + cast: [ + { + cast_id: number; + character: string; + credit_id: string; + gender?: number; + id: number; + name: string; + order: number; + profile_path?: string; + }, + ]; + crew: [ + { + credit_id: string; + department: string; + gender?: number; + id: number; + job: string; + name: string; + profile_path?: string; + }, + ]; +} diff --git a/src/domains/Movie/api/Credits/Response.ts b/src/domains/Movie/api/Credits/Response.ts new file mode 100644 index 0000000..cd876fb --- /dev/null +++ b/src/domains/Movie/api/Credits/Response.ts @@ -0,0 +1,7 @@ +import Cast from 'domains/Movie/api/Credits/dtos/Cast'; +import Crew from 'domains/Movie/api/Credits/dtos/Crew'; + +export default interface Response { + cast: Cast[]; + crew: Crew[]; +} diff --git a/src/domains/Movie/api/Credits/dtos/Cast.ts b/src/domains/Movie/api/Credits/dtos/Cast.ts new file mode 100644 index 0000000..a647d31 --- /dev/null +++ b/src/domains/Movie/api/Credits/dtos/Cast.ts @@ -0,0 +1,10 @@ +export default interface Cast { + castId: number; + character: string; + creditId: string; + gender?: number; + id: number; + name: string; + order: number; + profile: string; +} diff --git a/src/domains/Movie/api/Credits/dtos/Crew.ts b/src/domains/Movie/api/Credits/dtos/Crew.ts new file mode 100644 index 0000000..dc1054b --- /dev/null +++ b/src/domains/Movie/api/Credits/dtos/Crew.ts @@ -0,0 +1,9 @@ +export default interface Crew { + creditId: string; + department: string; + gender?: number; + id: number; + job: string; + name: string; + profile: string; +} diff --git a/src/domains/Movie/api/Details/Params.ts b/src/domains/Movie/api/Details/Params.ts new file mode 100644 index 0000000..e1d07a0 --- /dev/null +++ b/src/domains/Movie/api/Details/Params.ts @@ -0,0 +1,3 @@ +export default interface Params { + appendToResponse?: string; +} diff --git a/src/domains/Movie/api/Details/RawResponse.ts b/src/domains/Movie/api/Details/RawResponse.ts index 91f6e41..b7299ed 100644 --- a/src/domains/Movie/api/Details/RawResponse.ts +++ b/src/domains/Movie/api/Details/RawResponse.ts @@ -1,3 +1,6 @@ +import Recommendations from 'domains/Movie/api/Recommendations/RawResponse'; +import Credits from 'domains/Movie/api/Credits/RawResponse'; + export default interface RawResponse { poster_path?: string; budget: number; @@ -9,13 +12,20 @@ export default interface RawResponse { name: string; }, ]; + homepage?: string; id: number; original_title: string; original_language: string; title: string; backdrop_path?: string; popularity: number; + runtime: number; vote_count: number; video: boolean; vote_average: number; + tagline: string; + recommendations?: { + results: Recommendations[]; + }; + credits?: Credits; } diff --git a/src/domains/Movie/api/Details/Response.ts b/src/domains/Movie/api/Details/Response.ts index 0f0a2d9..adbd028 100644 --- a/src/domains/Movie/api/Details/Response.ts +++ b/src/domains/Movie/api/Details/Response.ts @@ -1,3 +1,6 @@ +import Recommendations from 'domains/Movie/api/Recommendations/Response'; +import Credits from 'domains/Movie/api/Credits/Response'; + export default interface Response { poster?: string; backdrop?: string; @@ -10,11 +13,19 @@ export default interface Response { name: string; }, ]; + genresNames: string; + homepage?: string; id: number; originalTitle: string; title: string; popularity: number; + runtime: string; voteCount: number; voteAverage: number; + tagline: string; favorite: boolean; + + recommendations?: Recommendations[]; + credits?: Credits; + directorName?: string; } diff --git a/src/domains/Movie/api/Details/index.ts b/src/domains/Movie/api/Details/index.ts index df86bba..3c7ddcc 100644 --- a/src/domains/Movie/api/Details/index.ts +++ b/src/domains/Movie/api/Details/index.ts @@ -1,33 +1,51 @@ import tmdb from 'services/api/tmdb'; +import Params from 'domains/Movie/api/Details/Params'; import RawResponse from 'domains/Movie/api/Details/RawResponse'; import Response from 'domains/Movie/api/Details/Response'; +import Recommendations from 'domains/Movie/api/Recommendations/Response'; +import Credits from 'domains/Movie/api/Credits/Response'; import formatDate from 'shared/utils/formatDate'; import formatTmdbImage from 'shared/utils/formatTmdbImage'; +import Crew from 'domains/Movie/api/Credits/dtos/Crew'; +import Cast from 'domains/Movie/api/Credits/dtos/Cast'; +import { arrayToString } from 'shared/utils'; -const Details = async (movieId: number): Promise => { - const response = await rawPopular(movieId); +const Details = async (movieId: number, params?: Params): Promise => { + const response = await rawPopular(movieId, params); return parseResponse(response); }; -export const rawPopular = async (movieId: number): Promise => { - const response = await tmdb.get(`/movie/${movieId}`); +export const rawPopular = async ( + movieId: number, + params?: Params, +): Promise => { + const response = await tmdb.get(`/movie/${movieId}`, { + params: { append_to_response: params?.appendToResponse }, + }); return response.data; }; const parseResponse = (movie: RawResponse): Response => { - const parsedMovie = { + let parsedMovie = { overview: movie.overview, budget: movie.budget, genres: movie.genres, + genresNames: arrayToString(movie.genres, 'name'), id: movie.id, originalTitle: movie.original_title, title: movie.title, popularity: movie.popularity, voteCount: movie.vote_count, voteAverage: movie.vote_average, + runtime: `${movie.runtime} min`, + tagline: movie.tagline, + + directorName: movie.credits?.crew.find( + person => person.job.toUpperCase() === 'DIRECTOR', + )?.name, releaseDate: formatDate({ value: movie.release_date }), poster: formatTmdbImage({ value: movie.poster_path }), @@ -35,6 +53,41 @@ const parseResponse = (movie: RawResponse): Response => { favorite: false, } as Response; + const recommendations = movie.recommendations?.results.map( + recommendation => ({ + poster: formatTmdbImage({ value: recommendation.poster_path }), + backdrop: formatTmdbImage({ value: recommendation.poster_path }), + id: recommendation.id, + title: recommendation.title, + favorite: false, + }), + ) as Recommendations[]; + + const cast = movie.credits?.cast.slice(0, 15).map(person => ({ + order: person.order, + id: person.id, + name: person.name, + character: person.character, + castId: person.cast_id, + creditId: person.credit_id, + gender: person.gender, + profile: formatTmdbImage({ value: person.profile_path }), + })) as Cast[]; + + const crew = movie.credits?.crew.map(person => ({ + id: person.id, + name: person.name, + job: person.job, + department: person.department, + creditId: person.credit_id, + gender: person.gender, + profile: formatTmdbImage({ value: person.profile_path }), + })) as Crew[]; + + const credits = { cast, crew } as Credits; + + parsedMovie = { ...parsedMovie, recommendations, credits }; + return parsedMovie; }; diff --git a/src/domains/Movie/api/Recommendations/RawResponse.ts b/src/domains/Movie/api/Recommendations/RawResponse.ts new file mode 100644 index 0000000..63ebf95 --- /dev/null +++ b/src/domains/Movie/api/Recommendations/RawResponse.ts @@ -0,0 +1,15 @@ +export default interface RawResponse { + poster_path?: string; + overview: string; + release_date: string; + genres_ids: number[]; + id: number; + original_title: string; + original_language: string; + title: string; + backdrop_path?: string; + popularity: number; + vote_count: number; + video: boolean; + vote_average: number; +} diff --git a/src/domains/Movie/api/Recommendations/Response.ts b/src/domains/Movie/api/Recommendations/Response.ts new file mode 100644 index 0000000..fd046d8 --- /dev/null +++ b/src/domains/Movie/api/Recommendations/Response.ts @@ -0,0 +1,14 @@ +export default interface Response { + poster?: string; + backdrop?: string; + id: number; + title: string; + favorite: boolean; + // overview: string; + // releaseDate: string; + // genresIds: number[]; + // originalTitle: string; + // popularity: number; + // voteCount: number; + // voteAverage: number; +} diff --git a/src/domains/Movie/api/Recommendations/index.ts b/src/domains/Movie/api/Recommendations/index.ts new file mode 100644 index 0000000..f61c556 --- /dev/null +++ b/src/domains/Movie/api/Recommendations/index.ts @@ -0,0 +1,46 @@ +import tmdb from 'services/api/tmdb'; + +import RawResponse from 'domains/Movie/api/Recommendations/RawResponse'; +import Response from 'domains/Movie/api/Recommendations/Response'; +import formatDate from 'shared/utils/formatDate'; +import formatTmdbImage from 'shared/utils/formatTmdbImage'; + +const Recommendations = async (movieId: number): Promise => { + const response = await rawPopular(movieId); + + return parseResponse(response); +}; + +export const rawPopular = async (movieId: number): Promise => { + const response = await tmdb.get(`/movie/${movieId}/recommendations/`); + + return response.data.results; +}; + +const parseResponse = (rawResponse: RawResponse[]): Response[] => { + let response = [] as Response[]; + + rawResponse.forEach(movie => { + const parsedMovie = { + overview: movie.overview, + genresIds: movie.genres_ids, + id: movie.id, + originalTitle: movie.original_title, + title: movie.title, + popularity: movie.popularity, + voteCount: movie.vote_count, + voteAverage: movie.vote_average, + + releaseDate: formatDate({ value: movie.release_date }), + poster: formatTmdbImage({ value: movie.poster_path }), + backdrop: formatTmdbImage({ value: movie.backdrop_path }), + favorite: false, + } as Response; + + response = [...response, parsedMovie]; + }); + + return response; +}; + +export default Recommendations; diff --git a/src/domains/Movie/api/index.ts b/src/domains/Movie/api/index.ts index aeebfaa..48e555a 100644 --- a/src/domains/Movie/api/index.ts +++ b/src/domains/Movie/api/index.ts @@ -1,3 +1,4 @@ export { default as Details } from './Details'; export { default as NowPlaying } from './NowPlaying'; export { default as Popular } from './Popular'; +export { default as Recommendations } from './Recommendations'; diff --git a/src/routes/enums/index.ts b/src/routes/enums/index.ts index 71672ce..7edac3e 100644 --- a/src/routes/enums/index.ts +++ b/src/routes/enums/index.ts @@ -3,6 +3,7 @@ enum Route { LOGIN = '/login', SIGNUP = '/signup', MOVIE = '/movie', + PERSON = '/person', PROFILE = '/profile', FAVORITES = '/favorites', } diff --git a/src/routes/index.tsx b/src/routes/index.tsx index f19dc4e..d05ff3a 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -9,7 +9,7 @@ import { Home, Movie, Login, Signup, Profile, Favorites } from 'screens'; const Routes: React.FC = () => ( - + diff --git a/src/screens/Movie/dtos/Params.ts b/src/screens/Movie/dtos/Params.ts new file mode 100644 index 0000000..09eef17 --- /dev/null +++ b/src/screens/Movie/dtos/Params.ts @@ -0,0 +1,3 @@ +export default interface Params { + id: string; +} diff --git a/src/screens/Movie/index.tsx b/src/screens/Movie/index.tsx index 9a9e388..b164096 100644 --- a/src/screens/Movie/index.tsx +++ b/src/screens/Movie/index.tsx @@ -1,12 +1,113 @@ -import React from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; -import { Container } from './styles'; +import Params from 'screens/Movie/dtos/Params'; +import MovieDetails from 'domains/Movie/api/Details/Response'; +import { Color } from 'shared/enums'; +import { Details } from 'domains/Movie/api'; + +import { ColumnLayout, Container, Movie as Poster } from 'components'; +import { Header, PersonList, MovieList, Footer } from 'containers'; +import { + ContentContainer, + MovieContainer, + PosterContainer, + MovieDetailsContainer, + TitleContainer, + Title, + Subtitle, + Tagline, + OverviewContainer, + OverviewTitle, + Overview, + VoteAverage, + VoteAverageTitle, + Director, + DirectorTitle, + HeaderBackground, +} from './styles'; + +const Movie: React.FC = () => { + const { id } = useParams(); + const [movie, setMovie] = useState({} as MovieDetails); + const [isLoading, setIsLoading] = useState(false); + + const getMovie = useCallback(async () => { + try { + setIsLoading(true); + const params = { + appendToResponse: 'recommendations,credits', + }; + + const response = await Details(+id, params); + + setMovie(response); + return response; + } catch (error) { + console.log('getMovie -> error', error); + } finally { + setIsLoading(false); + } + }, [id]); + + useEffect(() => { + window.scrollTo(0, 0); + getMovie(); + }, [getMovie]); -const Movie: React.FC = () => { return ( - -

Movie Screen

-
+ +
+ + backdrop + + + + + + + + + + + {movie.title} + + {movie.releaseDate} | {movie.genresNames} | {movie.runtime} + + + {movie.tagline && {`"${movie.tagline}"`}} + + Sinopse + {movie.overview} + + + Votação do público:{' '} + {movie.voteAverage} + + + Diretor: + {movie.directorName} + + + + + + + + + +