diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index c1a6e13db..ecda0105a 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -9,7 +9,7 @@ const useMetaDetails = require('./useMetaDetails'); const useMetaExtensions = require('./useMetaExtensions'); const styles = require('./styles'); -const MetaDetails = ({ urlParams }) => { +const MetaDetails = ({ urlParams, queryParams }) => { const metaDetails = useMetaDetails(urlParams); const { tabs, selectedMetaExtension, clearSelectedMetaExtension } = useMetaExtensions(metaDetails.meta_resources); const metaResourceRef = React.useMemo(() => { @@ -26,6 +26,15 @@ const MetaDetails = ({ urlParams }) => { }, [metaDetails]); const streamsResourceRef = metaDetails.selected !== null ? metaDetails.selected.streams_resource_ref : null; const streamsResources = metaDetails.streams_resources; + const seasonQueryParam = React.useMemo(() => { + return queryParams.has('season') && !isNaN(queryParams.get('season')) ? + parseInt(queryParams.get('season')) + : + null; + }, [queryParams]); + const seasonOnSelect = React.useCallback((event) => { + window.location.replace(`#/metadetails/${selectedMetaResource.request.path.type_name}/${selectedMetaResource.request.path.id}?season=${event.value}`); + }, [selectedMetaResource]); const selectedVideo = React.useMemo(() => { return streamsResourceRef !== null && selectedMetaResource !== null ? selectedMetaResource.content.content.videos.reduce((result, video) => { @@ -125,6 +134,8 @@ const MetaDetails = ({ urlParams }) => { : null diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 5ea7e8b5c..a6a53ed35 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -7,20 +7,44 @@ const Image = require('stremio/common/Image'); const SearchBar = require('stremio/common/SearchBar'); const SeasonsBar = require('./SeasonsBar'); const Video = require('./Video'); -const useSelectableSeasons = require('./useSelectableSeasons'); const styles = require('./styles'); -const VideosList = ({ className, metaResource }) => { +const VideosList = ({ className, metaResource, season, seasonOnSelect }) => { const videos = React.useMemo(() => { return metaResource && metaResource.content.type === 'Ready' ? metaResource.content.content.videos : []; }, [metaResource]); - const [seasons, selectedSeason, videosForSeason, selectSeason] = useSelectableSeasons(videos); - const seasonOnSelect = React.useCallback((event) => { - selectSeason(event.value); - }, []); + const seasons = React.useMemo(() => { + return videos + .map(({ season }) => season) + .filter((season, index, seasons) => { + return season !== null && + !isNaN(season) && + typeof season === 'number' && + seasons.indexOf(season) === index; + }) + .sort((a, b) => a - b); + }, [videos]); + const selectedSeason = React.useMemo(() => { + return seasons.includes(season) ? + season + : + seasons.length > 0 ? + seasons[seasons.length - 1] + : + null; + }, [seasons, season]); + const videosForSeason = React.useMemo(() => { + return videos + .filter((video) => { + return selectedSeason === null || video.season === selectedSeason; + }) + .sort((a, b) => { + return a.episode - b.episode; + }); + }, [videos, selectedSeason]); const [search, setSearch] = React.useState(''); const searchInputOnChange = React.useCallback((event) => { setSearch(event.currentTarget.value); @@ -88,7 +112,9 @@ const VideosList = ({ className, metaResource }) => { VideosList.propTypes = { className: PropTypes.string, - metaResource: PropTypes.object + metaResource: PropTypes.object, + season: PropTypes.number, + seasonOnSelect: PropTypes.func }; module.exports = VideosList; diff --git a/src/routes/MetaDetails/VideosList/useSelectableSeasons.js b/src/routes/MetaDetails/VideosList/useSelectableSeasons.js deleted file mode 100644 index 980625ee1..000000000 --- a/src/routes/MetaDetails/VideosList/useSelectableSeasons.js +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2017-2020 Smart code 203358507 - -const React = require('react'); - -const reducer = (state, action) => { - switch (action.type) { - case 'videos-changed': { - const seasons = action.videos - .map(({ season }) => season) - .filter((season, index, seasons) => { - return season !== null && - !isNaN(season) && - typeof season === 'number' && - seasons.indexOf(season) === index; - }) - .sort((a, b) => a - b); - const selectedSeason = seasons.includes(state.selectedSeason) ? - state.selectedSeason - : - seasons.length > 0 ? - seasons[seasons.length - 1] - : - null; - return { - ...state, - videos: action.videos, - seasons, - selectedSeason - }; - } - case 'season-changed': { - const selectedSeason = state.seasons.includes(action.season) ? - action.season - : - state.season; - return { - ...state, - selectedSeason - }; - } - default: { - return state; - } - } -}; - -const initializer = (videos) => { - const initialState = { - videos: [], - seasons: [], - selectedSeason: null - }; - const initAction = { - type: 'videos-changed', - videos - }; - - return reducer(initialState, initAction); -}; - -const useSelectableSeasons = (videos) => { - const [state, dispatch] = React.useReducer( - reducer, - videos, - initializer - ); - const selectSeason = React.useCallback((season) => { - dispatch({ - type: 'season-changed', - season - }); - }, []); - const videosForSeason = React.useMemo(() => { - return state.videos - .filter((video) => { - return state.selectedSeason === null || video.season === state.selectedSeason; - }) - .sort((a, b) => { - return a.episode - b.episode; - }); - }, [state.videos, state.selectedSeason]); - React.useEffect(() => { - dispatch({ - type: 'videos-changed', - videos - }); - }, [videos]); - return [state.seasons, state.selectedSeason, videosForSeason, selectSeason]; -}; - -module.exports = useSelectableSeasons; diff --git a/tests/hooks.spec.js b/tests/hooks.spec.js deleted file mode 100644 index 7a68de98e..000000000 --- a/tests/hooks.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2017-2020 Smart code 203358507 - -const { renderHook, act } = require('@testing-library/react-hooks'); -const useSelectableSeasons = require('../src/routes/MetaDetails/VideosList/useSelectableSeasons'); - -const videos = [{ 'season': 4 }, { 'season': 5 }, { 'season': 4 }, { 'season': 7 }]; - -describe('hooks tests', () => { - describe('useSelectableSeasons hook', () => { - it('match 7', async () => { - const { result } = renderHook(() => useSelectableSeasons(videos)); - const [, selectedSeason] = result.current; - expect(selectedSeason).toBe(7); - }); - - it('match 5', async () => { - const { result } = renderHook(() => useSelectableSeasons(videos)); - - act(() => { - const [, , , selectSeason] = result.current; - selectSeason(5); - }); - - const [, selectedSeason] = result.current; - expect(selectedSeason).toBe(5); - }); - - it('not match 6', async () => { - const { result } = renderHook(() => useSelectableSeasons(videos)); - - act(() => { - const [, , , selectSeason] = result.current; - selectSeason(6); - }); - - const [, selectedSeason] = result.current; - expect(selectedSeason).toBe(undefined); - }); - - it('not match $', async () => { - const { result } = renderHook(() => useSelectableSeasons(videos)); - - act(() => { - const [, , , selectSeason] = result.current; - selectSeason('$'); - }); - - const [, selectedSeason] = result.current; - expect(selectedSeason).toBe(undefined); - }); - }); -});