From d951bd6596c443db24b711d24f8de547cc609123 Mon Sep 17 00:00:00 2001 From: AshDyson Date: Sat, 20 Apr 2024 18:12:14 +0100 Subject: [PATCH] chore(fe): various error catches + split redux genres --- pkg/frontend/src/components/reviewButtons.js | 2 +- pkg/frontend/src/pages/_app.js | 9 +- pkg/frontend/src/pages/movie/[pid].js | 6 +- pkg/frontend/src/pages/multi/company/[pid].js | 159 ++++++++++++++++++ pkg/frontend/src/pages/multi/genre/[pid].js | 11 +- pkg/frontend/src/pages/tv/[pid].js | 6 +- pkg/frontend/src/pages/tv/network/[pid].js | 20 ++- .../src/redux/reducers/media/reducer.js | 70 +++++++- pkg/frontend/src/services/media.service.js | 73 +++++++- .../src/styles/views/errorHandler.module.scss | 4 +- 10 files changed, 327 insertions(+), 33 deletions(-) create mode 100644 pkg/frontend/src/pages/multi/company/[pid].js diff --git a/pkg/frontend/src/components/reviewButtons.js b/pkg/frontend/src/components/reviewButtons.js index 4f096d8f8..6de646aeb 100644 --- a/pkg/frontend/src/components/reviewButtons.js +++ b/pkg/frontend/src/components/reviewButtons.js @@ -25,7 +25,7 @@ export default function ReviewButtons({ } function isReviewed() { - if (redux_reviews && redux_reviews.length > 0 && currentUser) { + if (data && redux_reviews && redux_reviews.length > 0 && currentUser) { const review = redux_reviews.filter((r) => { return r.tmdb_id === data.id.toString() && r.user === currentUser.id; }); diff --git a/pkg/frontend/src/pages/_app.js b/pkg/frontend/src/pages/_app.js index d335d6c81..ec8d8a0fc 100644 --- a/pkg/frontend/src/pages/_app.js +++ b/pkg/frontend/src/pages/_app.js @@ -31,7 +31,7 @@ import Admin from './admin/index'; // Pages import Home from './index'; import Movie from './movie/[pid]'; -import Studio from './movie/studio/[pid]'; +import Company from './multi/company/[pid]'; import Genre from './multi/genre/[pid]'; import MyAccount from './myAccount'; import People from './people/[pid]'; @@ -39,7 +39,6 @@ import Requests from './requests'; import Search from './search'; import Setup from './setup'; import Show from './tv/[pid]'; -import Network from './tv/network/[pid]'; const mapStateToProps = (state) => { return { @@ -340,10 +339,11 @@ function Petio({ redux_pos }) { /> - @@ -370,10 +370,11 @@ function Petio({ redux_pos }) { /> - diff --git a/pkg/frontend/src/pages/movie/[pid].js b/pkg/frontend/src/pages/movie/[pid].js index e1f0cfe14..341d2d4e4 100644 --- a/pkg/frontend/src/pages/movie/[pid].js +++ b/pkg/frontend/src/pages/movie/[pid].js @@ -48,6 +48,7 @@ function Movie({ const { pid } = useParams(); const movieData = redux_movies[pid]; const [collection, setCollection] = useState(false); + const [error, setError] = useState(false); useEffect(() => { function handleResize() { @@ -89,9 +90,10 @@ function Movie({ useEffect(() => { async function getMovieDetails() { try { - media.getMovie(pid); + await media.getMovie(pid); getReviews(); } catch (e) { + setError(true); console.log(e); } } @@ -205,7 +207,7 @@ function Movie({ } } - if (movieData === 'error') { + if (error) { return ; } diff --git a/pkg/frontend/src/pages/multi/company/[pid].js b/pkg/frontend/src/pages/multi/company/[pid].js new file mode 100644 index 000000000..46fc3d197 --- /dev/null +++ b/pkg/frontend/src/pages/multi/company/[pid].js @@ -0,0 +1,159 @@ +import { useEffect, useState } from 'react'; +import { LazyLoadImage } from 'react-lazy-load-image-component'; +import 'react-lazy-load-image-component/src/effects/opacity.css'; +import { connect } from 'react-redux'; +import { useParams } from 'react-router-dom'; + +import NotFound from '../../404'; +import Grid from '../../../components/grid'; +import Hero from '../../../components/hero'; +import { Loading } from '../../../components/loading'; +import Meta from '../../../components/meta'; +import media from '../../../services/media.service'; +import hero from '../../../styles/components/hero.module.scss'; +import styles from '../../../styles/views/company.module.scss'; + +const mapStateToProps = (state) => { + return { + redux_studios: state.media.studios, + redux_networks: state.media.networks, + redux_studioData: state.media.studioData, + redux_networkData: state.media.networkData, + }; +}; + +function Company({ + newNotification, + type, + redux_studios, + redux_studioData, + redux_networks, + redux_networkData, +}) { + const [companyName, setCompanyName] = useState(null); + const [companyLogo, setCompanyLogo] = useState(null); + const [total, setTotal] = useState(1); + const [featured, setFeatured] = useState(false); + const { pid } = useParams(); + const [loadingMore, setLoadingMore] = useState(false); + const [page, setPage] = useState(1); + const [error, setError] = useState(false); + const companyData = + type === 'studio' + ? redux_studioData[pid] || null + : redux_networkData[pid] || null; + const companyInfo = + type === 'studio' + ? redux_studios[pid] || null + : redux_networks[pid] || null; + + useEffect(() => { + if (companyData) { + if (companyData.results) setFeatured(companyData.results[0]); + setPage(companyData.page); + setTotal(companyData.total_pages); + } + }, [companyData]); + + useEffect(() => { + if (companyInfo) { + setCompanyName(companyInfo.name); + setCompanyLogo(companyInfo.logo_path); + } + }, [companyInfo]); + + useEffect(() => { + async function getCoDetails() { + try { + await media.companyLookup(type, 1, pid); + if (type === 'studio') { + await media.getStudio(pid); + } else { + await media.getNetwork(pid); + } + } catch (e) { + console.log(e); + setError(true); + } + } + + getCoDetails(); + }, [pid, type]); + + useEffect(() => { + async function loadMore() { + if (loadingMore || page === total) return; + try { + setLoadingMore(true); + await media.companyLookup(type, page + 1, pid); + setLoadingMore(false); + } catch (e) { + console.log(e); + } + } + + function handleScroll() { + if ( + window.innerHeight * 2 + window.scrollY >= + document.body.offsetHeight + ) { + // you're at the bottom of the page + loadMore(); + } + } + + window.addEventListener('scroll', handleScroll); + + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, [loadingMore, page, total, pid, type]); + + // if (!coData) return ; + + if (error) return ; + + return ( +
+ +
+
+
+
+ {companyLogo ? ( + + ) : ( +

{companyName || ' '}

+ )} +
+
+
+
+ {featured ? ( + + ) : null} +
+
+ +
+ ); +} + +export default connect(mapStateToProps)(Company); diff --git a/pkg/frontend/src/pages/multi/genre/[pid].js b/pkg/frontend/src/pages/multi/genre/[pid].js index 0bb47fe68..1b8e3fa67 100644 --- a/pkg/frontend/src/pages/multi/genre/[pid].js +++ b/pkg/frontend/src/pages/multi/genre/[pid].js @@ -22,16 +22,17 @@ function Genre({ type, newNotification, redux_genreData }) { const [genreName, setGenreName] = useState(''); // const [movies, setMovies] = useState(false); const [total, setTotal] = useState(1); - const [featuredMovie, setFeaturedMovie] = useState(false); + const [featured, setFeatured] = useState(false); const { pid } = useParams(); const [loadingMore, setLoadingMore] = useState(false); const [page, setPage] = useState(1); const [query, setQuery] = useState(null); - const genreData = redux_genreData[pid] || null; + const mediaType = type === 'movie' ? 'movies' : 'tv'; + const genreData = redux_genreData[mediaType][pid] || null; useEffect(() => { if (genreData) { - if (genreData.results) setFeaturedMovie(genreData.results[0]); + if (genreData.results) setFeatured(genreData.results[0]); setPage(genreData.page); setTotal(genreData.total_pages); } @@ -139,10 +140,10 @@ function Genre({ type, newNotification, redux_genreData }) {
- {featuredMovie ? ( + {featured ? ( ) : null}
diff --git a/pkg/frontend/src/pages/tv/[pid].js b/pkg/frontend/src/pages/tv/[pid].js index dd69c6d64..d54e22438 100644 --- a/pkg/frontend/src/pages/tv/[pid].js +++ b/pkg/frontend/src/pages/tv/[pid].js @@ -45,6 +45,7 @@ function Tv({ const [mobile, setMobile] = useState(false); const [trailer, setTrailer] = useState(false); const [issuesOpen, setIssuesOpen] = useState(false); + const [error, setError] = useState(false); const { pid } = useParams(); const tvData = redux_tv[pid]; @@ -61,8 +62,9 @@ function Tv({ useEffect(() => { async function getTvDetails() { try { - media.getTv(pid); + await media.getTv(pid); } catch (e) { + setError(true); console.log(e); } } @@ -182,7 +184,7 @@ function Tv({ } } - if (tvData === 'error') { + if (error) { return ; } diff --git a/pkg/frontend/src/pages/tv/network/[pid].js b/pkg/frontend/src/pages/tv/network/[pid].js index 4c7222622..847e89153 100644 --- a/pkg/frontend/src/pages/tv/network/[pid].js +++ b/pkg/frontend/src/pages/tv/network/[pid].js @@ -26,9 +26,14 @@ export default function Network({ newNotification }) { async function getCoDetails() { try { const showData = await media.getNetwork(pid); - const tvLookup = await media.lookup('show', 1, { - with_networks: pid, - }); + const tvLookup = await media.companyLookup( + 'show', + 1, + { + with_networks: pid, + }, + pid, + ); setCoData(showData); setShows(tvLookup.results); setTotal(tvLookup.totalPages); @@ -49,7 +54,12 @@ export default function Network({ newNotification }) { async function loadMore() { if (loadingMore || !query || page === total) return; setLoadingMore(true); - const showsLookup = await media.lookup('show', page + 1, query); + const showsLookup = await media.companyLookup( + 'show', + page + 1, + query, + pid, + ); setShows([...shows, ...showsLookup.results]); setPage(page + 1); setLoadingMore(false); @@ -70,7 +80,7 @@ export default function Network({ newNotification }) { return () => { window.removeEventListener('scroll', handleScroll); }; - }, [loadingMore, query, page, total, shows]); + }, [loadingMore, query, page, total, shows, pid]); if (!coData) return ; diff --git a/pkg/frontend/src/redux/reducers/media/reducer.js b/pkg/frontend/src/redux/reducers/media/reducer.js index 4534c102e..51f9696e9 100644 --- a/pkg/frontend/src/redux/reducers/media/reducer.js +++ b/pkg/frontend/src/redux/reducers/media/reducer.js @@ -8,7 +8,14 @@ export default function ( movies: [], tv: [], }, - genreData: {}, + genreData: { + movies: {}, + tv: {}, + }, + studios: {}, + studioData: {}, + networks: {}, + networkData: {}, searchQuery: '', searchResults: false, featured: false, @@ -98,12 +105,67 @@ export default function ( ...state, genreData: { ...state.genreData, + [action.mediaType]: { + ...state.genreData[action.type], + [action.id]: { + ...state.genreData[action.mediaType][action.id], + page: action.data.page, + totalPages: action.data.total_pages, + results: state.genreData[action.mediaType][action.id] + ? [ + ...state.genreData[action.mediaType][action.id].results, + ...action.data.results, + ] + : action.data.results, + }, + }, + }, + }; + case 'media/store-studio': + return { + ...state, + studios: { + ...state.studios, + [action.id]: action.data, + }, + }; + case 'media/store-network': + return { + ...state, + networks: { + ...state.networks, + [action.id]: action.data, + }, + }; + case 'media/store-studio-results': + return { + ...state, + studioData: { + ...state.studioData, + [action.id]: { + ...state.studioData[action.id], + page: action.data.page, + totalPages: action.data.total_pages, + results: state.studioData[action.id] + ? [...state.studioData[action.id].results, ...action.data.results] + : action.data.results, + }, + }, + }; + case 'media/store-network-results': + return { + ...state, + networkData: { + ...state.networkData, [action.id]: { - ...state.genreData[action.id], + ...state.networkData[action.id], page: action.data.page, totalPages: action.data.total_pages, - results: state.genreData[action.id] - ? [...state.genreData[action.id].results, ...action.data.results] + results: state.networkData[action.id] + ? [ + ...state.networkData[action.id].results, + ...action.data.results, + ] : action.data.results, }, }, diff --git a/pkg/frontend/src/services/media.service.js b/pkg/frontend/src/services/media.service.js index 6ea3b55fe..4a4b1abd9 100644 --- a/pkg/frontend/src/services/media.service.js +++ b/pkg/frontend/src/services/media.service.js @@ -73,7 +73,7 @@ async function getMovie(id, minified = false, noextras = false) { return data; } catch (e) { updateStore({ - type: 'media/store-shows', + type: 'media/store-movies', shows: { [id]: 'error' }, }); throw e; @@ -146,14 +146,18 @@ async function getPerson(id) { } } -function getCompany(id) { +async function getStudio(id) { if (!id) throw 'No ID'; - return get(`/movie/company/${id}`); + const data = await get(`/movie/studio/${id}`); + updateStore({ type: 'media/store-studio', data: data, id: id }); + return data; } -function getNetwork(id) { +async function getNetwork(id) { if (!id) throw 'No ID'; - return get(`/show/network/${id}`); + const data = await get(`/show/network/${id}`); + updateStore({ type: 'media/store-network', data: data, id: id }); + return data; } async function genreLookup(type, page, params = {}, id) { @@ -168,7 +172,12 @@ async function genreLookup(type, page, params = {}, id) { } }); updateStore({ type: 'media/store-movies', movies: movies }); - updateStore({ type: 'media/store-genre-data', id: id, data: data }); + updateStore({ + type: 'media/store-genre-data', + id: id, + data: data, + mediaType: 'movies', + }); return data; } else if (type === 'show') { let shows = {}; @@ -179,7 +188,12 @@ async function genreLookup(type, page, params = {}, id) { } }); updateStore({ type: 'media/store-shows', shows: shows }); - updateStore({ type: 'media/store-genre-data', id: id, data: data }); + updateStore({ + type: 'media/store-genre-data', + id: id, + data: data, + mediaType: 'tv', + }); return data; } } catch (e) { @@ -188,6 +202,48 @@ async function genreLookup(type, page, params = {}, id) { } } +async function companyLookup(type, page, id) { + try { + if (type === 'studio') { + const data = await post(`/movie/discover`, { + page, + params: { + with_companies: id, + }, + }); + let movies = {}; + data.results.forEach((movie) => { + if (movie.id) { + movies[movie.id] = movie; + movies[movie.id].ready = true; + } + }); + updateStore({ type: 'media/store-movies', movies: movies }); + updateStore({ type: 'media/store-studio-results', id: id, data: data }); + return data; + } else if (type === 'network') { + const data = await post(`/show/discover`, { + page, + params: { + with_networks: id, + }, + }); + let shows = {}; + data.results.forEach((show) => { + if (show.id) { + shows[show.id] = show; + shows[show.id].ready = true; + } + }); + updateStore({ type: 'media/store-shows', shows: shows }); + updateStore({ type: 'media/store-network-results', id: id, data: data }); + return data; + } + } catch (e) { + throw `Error getting ${type === 'movies' ? 'Movies' : 'Shows'}`; + } +} + async function lookup(type, page, params = {}) { try { // return post(`/${type}/discover`, { page, params }); @@ -351,9 +407,10 @@ export default { getTv, getPerson, getDiscovery, - getCompany, + getStudio, getNetwork, genreLookup, + companyLookup, lookup, searchUpdate, search, diff --git a/pkg/frontend/src/styles/views/errorHandler.module.scss b/pkg/frontend/src/styles/views/errorHandler.module.scss index 703ff4ff2..eaae6f4fa 100644 --- a/pkg/frontend/src/styles/views/errorHandler.module.scss +++ b/pkg/frontend/src/styles/views/errorHandler.module.scss @@ -8,7 +8,7 @@ } p { - margin-top: calc(var(--gutter) * 2); + margin-top: calc(var(--spacing) * 2); } } @@ -16,7 +16,7 @@ margin-top: var(--spacing); background: var(--grey); padding: 20px; - margin-top: calc(var(--gutter) * 4); + margin-top: calc(var(--spacing) * 4); code { color: red;