Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add navigation via recommendations #521

Merged
merged 5 commits into from
Feb 3, 2025
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
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
1 change: 1 addition & 0 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const Card = ({
src={getTwicpicsUrl('tmdb', poster_path)}
ratio={MOVIE_POSTER_ASPECT_RATIO}
className="w-full h-full object-cover"
alt={title}
/>
</div>
<Title variant="cardTitle" className="text-wrap">
Expand Down
7 changes: 6 additions & 1 deletion src/components/Dialog/DialogContent.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react'
import styled, { css } from 'styled-components'
import { Dialog as ReakitDialog } from 'reakit/Dialog'
import get from 'utils/get'
Expand Down Expand Up @@ -34,6 +35,10 @@ const Dialog = styled(ReakitDialog)`
}
`

const DialogContent = props => <Dialog $animated={props.animated} {...props} />
const DialogContent = React.forwardRef((props, ref) => (
<Dialog $animated={props.animated} ref={ref} {...props} />
))

DialogContent.displayName = 'DialogContent'

export default DialogContent
11 changes: 7 additions & 4 deletions src/components/MovieContent/Desktop/DesktopMovieInfos.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react'
import styled from 'styled-components'
import { TwicImg } from '@twicpics/components/react'
import Typography from 'components/Typography'
import Rating from 'components/Rating'
import Poster from 'components/Poster'
import Crews from '../Crews'
import Socials from '../Socials'
import BackdropImage from '../BackdropImage'
import Tags from '../Tags'
import { getTwicpicsUrl } from '~/utils'
import { MOVIE_POSTER_ASPECT_RATIO } from '~/lib/constants'

const Descriptions = styled.div`
margin-left: 40px;
Expand Down Expand Up @@ -54,10 +56,11 @@ const DesktopMovieInfos = ({ movie }) => {
imageUrl={`https://image.tmdb.org/t/p/original/${movie.backdrop_path}`}
>
<Infos>
<Poster
src={poster_path}
<TwicImg
src={getTwicpicsUrl('tmdb', poster_path)}
alt={movie.title}
style={{ height: 360, flexShrink: 0 }}
ratio={MOVIE_POSTER_ASPECT_RATIO}
className="object-cover w-[240px] h-[360px] shrink-0 rounded-lg"
/>
<Descriptions>
<Typography variant="h1" style={{ textTransform: 'uppercase' }}>
Expand Down
11 changes: 7 additions & 4 deletions src/components/MovieContent/Mobile/MobileLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, { useMemo } from 'react'
import { useTranslation } from 'next-i18next'
import styled from 'styled-components'
import { TwicImg } from '@twicpics/components/react'
import { useTabState } from 'reakit/Tab'
import { Tab, TabList, TabPanel } from 'components/Tab'
import Typography from 'components/Typography'
import Providers from '../Providers'
import MobileMovieInfos from './MobileMovieInfos'
import Cast from '../Cast'
import BackdropImage from '../BackdropImage'
import Poster from 'components/Poster'
import SectionHeading from './SectionHeading'
import Recommendations from '../Recommendations'
import { useSimilarMovies } from '~/hooks/useSimilarMovies'
import { getTwicpicsUrl } from '~/utils'
import { MOVIE_POSTER_ASPECT_RATIO } from '~/lib/constants'

const StyledTabList = styled(TabList)`
display: flex;
Expand All @@ -27,10 +29,11 @@ const Head = ({ tab, movie }) => {
<BackdropImage
imageUrl={`https://image.tmdb.org/t/p/w780/${backdrop_path}`}
>
<Poster
src={poster_path}
<TwicImg
src={getTwicpicsUrl('tmdb', poster_path)}
alt={movie.title}
style={{ height: 360, flexShrink: 0, marginTop: 120 }}
ratio={MOVIE_POSTER_ASPECT_RATIO}
className="object-cover w-[240px] h-[360px] shrink-0 rounded-lg mt-32"
/>
<StyledTabList {...tab} aria-label="movie tabs">
<Tab {...tab} id="overview">
Expand Down
24 changes: 16 additions & 8 deletions src/components/MovieContent/Recommendations.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import clsx from 'clsx'
import React from 'react'
import Card from '~/components/Card'
import { MovieContext } from '~/context/MovieContext'
import type { MovieData } from '~/types'

interface RecommendationsProps {
Expand All @@ -11,6 +13,7 @@ export default function Recommendations({
movies,
className,
}: RecommendationsProps) {
const { setCurrentMovie } = React.useContext(MovieContext)
return (
<div className={clsx('', className)}>
{movies.length === 0 ? (
Expand All @@ -20,15 +23,20 @@ export default function Recommendations({
) : (
<div className="flex flex-wrap gap-4">
{movies.map(movie => (
<Card
<button
key={movie.id}
id={movie.id}
title={movie.title}
poster_path={movie.poster_path}
release_date={movie.release_date}
vote_average={movie.vote_average}
className="w-32"
/>
onClick={() => setCurrentMovie(movie)}
className="text-left"
>
<Card
id={movie.id}
title={movie.title}
poster_path={movie.poster_path}
release_date={movie.release_date}
vote_average={movie.vote_average}
className="w-32"
/>
</button>
))}
</div>
)}
Expand Down
13 changes: 12 additions & 1 deletion src/components/MoviesList/MovieModalContent.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react'
import React, { useEffect, useContext, useRef } from 'react'
import styled from 'styled-components'
import { DialogBackdrop, DialogContent } from 'components/Dialog'
import { Cross } from 'components/icons'
import IconButton from 'components/IconButton'
import MovieContent from 'components/MovieContent'
import get from 'utils/get'
import { MovieContext } from '~/context/MovieContext'

const Close = styled(IconButton)`
position: absolute;
Expand All @@ -18,13 +19,23 @@ const Close = styled(IconButton)`
`

const MovieModalContent = ({ dialog, hit }) => {
const { currentMovie } = useContext(MovieContext)
const contentRef = useRef(null)

useEffect(() => {
if (currentMovie && contentRef.current) {
contentRef.current.scrollTo({ top: 0, behavior: 'smooth' })
}
}, [currentMovie])

return (
<DialogBackdrop {...dialog}>
<Close rounded onClick={() => dialog.hide()}>
<Cross width={15} />
</Close>
<DialogContent
{...dialog}
ref={contentRef}
tabIndex={0}
aria-label={hit?.title || 'Movie infos'}
data-cy="movie-detail"
Expand Down
42 changes: 24 additions & 18 deletions src/components/MoviesList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useDialogState } from 'reakit/Dialog'
import MovieModalContent from './MovieModalContent'
import Card from 'components/Card'
import { DialogDisclosure } from 'components/Dialog'
import { MovieContext, MovieContextProvider } from '~/context/MovieContext'

const Hits = styled(ISHits)`
ol {
Expand Down Expand Up @@ -51,7 +52,8 @@ const Disclosure = styled(DialogDisclosure)`

const MoviesList = () => {
const { t } = useTranslation('common')
const [currentMovie, setCurrentMovie] = React.useState()
const [movie, setMovie] = React.useState(null)
const { currentMovie } = React.useContext(MovieContext)
const dialog = useDialogState()
const cardsRef = React.useRef([])

Expand All @@ -65,23 +67,27 @@ const MoviesList = () => {
}, [dialog.visible])

return (
<Wrapper as="section">
<Infos title={t('movies')} />
<Hits
hitComponent={({ hit }) => (
<Disclosure
ref={ref => (cardsRef.current[hit.objectID] = ref)}
{...dialog}
onClick={() => {
setCurrentMovie(hit)
}}
>
<Card {...hit} />
</Disclosure>
)}
/>
<MovieModalContent hit={currentMovie} dialog={dialog} />
</Wrapper>
<MovieContextProvider
value={{ currentMovie: movie, setCurrentMovie: setMovie }}
>
<Wrapper as="section">
<Infos title={t('movies')} />
<Hits
hitComponent={({ hit }) => (
<Disclosure
ref={ref => (cardsRef.current[hit.objectID] = ref)}
{...dialog}
onClick={() => {
setMovie(hit)
}}
>
<Card {...hit} />
</Disclosure>
)}
/>
<MovieModalContent hit={movie} dialog={dialog} />
</Wrapper>
</MovieContextProvider>
)
}

Expand Down
47 changes: 0 additions & 47 deletions src/components/Poster.js

This file was deleted.

18 changes: 18 additions & 0 deletions src/context/MovieContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createContext, Dispatch, SetStateAction } from 'react'
import { MovieData as Movie } from '~/types'

export interface MovieContextProps {
currentMovie: Movie | null
setCurrentMovie: Dispatch<SetStateAction<Movie | null>>
}

export const movieContextDefaultValue: MovieContextProps = {
currentMovie: null,
setCurrentMovie: () => {},
}

export const MovieContext = createContext<MovieContextProps>(
movieContextDefaultValue
)

export const MovieContextProvider = MovieContext.Provider
Loading
Loading