From b924f72d861add4759d2fecda6f7f6f160fa65af Mon Sep 17 00:00:00 2001 From: Lucas Teixeira Date: Sun, 25 Oct 2020 10:28:46 -0300 Subject: [PATCH 1/4] WJ-19 - New: Movie page, request, recommendations; --- package.json | 1 + src/components/EnvironmentLabel/index.tsx | 6 +- src/components/Movie/dtos/ContainerProps.ts | 3 + src/components/Movie/dtos/index.ts | 4 +- src/components/Movie/index.tsx | 4 +- src/components/Movie/styles.ts | 7 +- src/components/index.ts | 2 + src/domains/Movie/api/Details/Params.ts | 3 + src/domains/Movie/api/Details/RawResponse.ts | 5 ++ src/domains/Movie/api/Details/Response.ts | 4 + src/domains/Movie/api/Details/index.ts | 29 +++++-- .../Movie/api/Recommendations/RawResponse.ts | 15 ++++ .../Movie/api/Recommendations/Response.ts | 14 ++++ .../Movie/api/Recommendations/index.ts | 46 +++++++++++ src/domains/Movie/api/index.ts | 1 + src/routes/index.tsx | 2 +- src/screens/Movie/dtos/Params.ts | 3 + src/screens/Movie/index.tsx | 81 +++++++++++++++++-- src/screens/Movie/styles.ts | 35 ++++++-- version.json | 2 +- 20 files changed, 238 insertions(+), 29 deletions(-) create mode 100644 src/components/Movie/dtos/ContainerProps.ts create mode 100644 src/domains/Movie/api/Details/Params.ts create mode 100644 src/domains/Movie/api/Recommendations/RawResponse.ts create mode 100644 src/domains/Movie/api/Recommendations/Response.ts create mode 100644 src/domains/Movie/api/Recommendations/index.ts create mode 100644 src/screens/Movie/dtos/Params.ts 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..cf46ee5 100644 --- a/src/components/Movie/styles.ts +++ b/src/components/Movie/styles.ts @@ -1,10 +1,11 @@ import styled from 'styled-components'; +import ContainerProps from './dtos/ContainerProps'; import { PosterHeight, PosterWidth, Size } from 'shared/enums'; -export const Container = styled.div` +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; diff --git a/src/components/index.ts b/src/components/index.ts index 4be78bd..fdcc89e 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,3 +1,5 @@ +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'; 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..7dd00ee 100644 --- a/src/domains/Movie/api/Details/RawResponse.ts +++ b/src/domains/Movie/api/Details/RawResponse.ts @@ -1,3 +1,5 @@ +import Recommendations from 'domains/Movie/api/Recommendations/RawResponse'; + export default interface RawResponse { poster_path?: string; budget: number; @@ -18,4 +20,7 @@ export default interface RawResponse { vote_count: number; video: boolean; vote_average: number; + recommendations?: { + results: Recommendations[]; + }; } diff --git a/src/domains/Movie/api/Details/Response.ts b/src/domains/Movie/api/Details/Response.ts index 0f0a2d9..53beff2 100644 --- a/src/domains/Movie/api/Details/Response.ts +++ b/src/domains/Movie/api/Details/Response.ts @@ -1,3 +1,5 @@ +import Recommendations from 'domains/Movie/api/Recommendations/Response'; + export default interface Response { poster?: string; backdrop?: string; @@ -17,4 +19,6 @@ export default interface Response { voteCount: number; voteAverage: number; favorite: boolean; + + recommendations?: Recommendations[]; } diff --git a/src/domains/Movie/api/Details/index.ts b/src/domains/Movie/api/Details/index.ts index df86bba..56e9dc3 100644 --- a/src/domains/Movie/api/Details/index.ts +++ b/src/domains/Movie/api/Details/index.ts @@ -1,24 +1,31 @@ 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 formatDate from 'shared/utils/formatDate'; import formatTmdbImage from 'shared/utils/formatTmdbImage'; -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, @@ -35,6 +42,18 @@ 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[]; + + parsedMovie = { ...parsedMovie, recommendations }; + 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/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..80b19e5 100644 --- a/src/screens/Movie/index.tsx +++ b/src/screens/Movie/index.tsx @@ -1,12 +1,81 @@ -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 { Footer, Header, MovieList } from 'containers'; +import { + ContentContainer, + MovieDetailsContainer, + 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', + }; + + 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

-
+ +
+ + + + + + + Outros conteúdos + {/* + + */} + + + +