feat(discover): add 'Popular People' slider
This commit is contained in:
@@ -3584,6 +3584,12 @@ paths:
|
||||
tags:
|
||||
- search
|
||||
parameters:
|
||||
- in: query
|
||||
name: sortBy
|
||||
schema:
|
||||
type: string
|
||||
enum: [popularity.asc, popularity.desc, release_date.asc, release_date.desc, revenue.asc, revenue.desc, primary_release_date.asc, primary_release_date.desc, original_title.asc, original_title.desc, vote_average.asc, vote_average.desc, vote_count.asc, vote_count.desc]
|
||||
default: popularity.desc
|
||||
- in: query
|
||||
name: page
|
||||
schema:
|
||||
@@ -3813,6 +3819,12 @@ paths:
|
||||
tags:
|
||||
- search
|
||||
parameters:
|
||||
- in: query
|
||||
name: sortBy
|
||||
schema:
|
||||
type: string
|
||||
enum: [popularity.asc, popularity.desc, vote_average.asc, vote_average.desc, vote_count.asc, vote_count.desc, first_air_date.asc, first_air_date.desc]
|
||||
default: popularity.desc
|
||||
- in: query
|
||||
name: page
|
||||
schema:
|
||||
@@ -4186,6 +4198,45 @@ paths:
|
||||
name:
|
||||
type: string
|
||||
example: Genre Name
|
||||
/discover/people:
|
||||
get:
|
||||
summary: Discover people
|
||||
description: Returns a list of people in a JSON object.
|
||||
tags:
|
||||
- search
|
||||
parameters:
|
||||
- in: query
|
||||
name: page
|
||||
schema:
|
||||
type: number
|
||||
example: 1
|
||||
default: 1
|
||||
- in: query
|
||||
name: language
|
||||
schema:
|
||||
type: string
|
||||
example: en
|
||||
responses:
|
||||
'200':
|
||||
description: Results
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: number
|
||||
example: 1
|
||||
totalPages:
|
||||
type: number
|
||||
example: 20
|
||||
totalResults:
|
||||
type: number
|
||||
example: 200
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/PersonResult'
|
||||
/request:
|
||||
get:
|
||||
summary: Get all requests
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
TmdbRegion,
|
||||
TmdbSearchMovieResponse,
|
||||
TmdbSearchMultiResponse,
|
||||
TmdbSearchPeopleResponse,
|
||||
TmdbSearchTvResponse,
|
||||
TmdbSeasonWithEpisodes,
|
||||
TmdbTvDetails,
|
||||
@@ -801,6 +802,27 @@ class TheMovieDb extends ExternalAPI {
|
||||
throw new Error(`[TMDb] Failed to fetch TV genres: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
public async getDiscoverPeople({
|
||||
page = 1,
|
||||
language = 'en',
|
||||
}: {
|
||||
page?: number;
|
||||
language?: string;
|
||||
}): Promise<TmdbSearchPeopleResponse> {
|
||||
try {
|
||||
const data = await this.get<TmdbSearchPeopleResponse>('/person/popular', {
|
||||
params: {
|
||||
page,
|
||||
language,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
throw new Error(`[TMDb] Failed to fetch popular people: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default TheMovieDb;
|
||||
|
||||
@@ -56,6 +56,10 @@ export interface TmdbSearchTvResponse extends TmdbPaginatedResponse {
|
||||
results: TmdbTvResult[];
|
||||
}
|
||||
|
||||
export interface TmdbSearchPeopleResponse extends TmdbPaginatedResponse {
|
||||
results: TmdbPersonResult[];
|
||||
}
|
||||
|
||||
export interface TmdbUpcomingMoviesResponse extends TmdbPaginatedResponse {
|
||||
dates: {
|
||||
maximum: string;
|
||||
|
||||
@@ -103,7 +103,7 @@ export const mapPersonResult = (
|
||||
name: personResult.name,
|
||||
popularity: personResult.popularity,
|
||||
adult: personResult.adult,
|
||||
mediaType: personResult.media_type,
|
||||
mediaType: personResult.media_type || 'person',
|
||||
profilePath: personResult.profile_path,
|
||||
knownFor: personResult.known_for.map((result) => {
|
||||
if (result.media_type === 'movie') {
|
||||
|
||||
@@ -567,4 +567,22 @@ discoverRoutes.get<{ language: string }, GenreSliderItem[]>(
|
||||
}
|
||||
);
|
||||
|
||||
discoverRoutes.get('/people', async (req, res) => {
|
||||
const tmdb = new TheMovieDb();
|
||||
|
||||
const data = await tmdb.getDiscoverPeople({
|
||||
page: Number(req.query.page),
|
||||
language: req.locale ?? (req.query.language as string),
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
page: data.page,
|
||||
totalPages: data.total_pages,
|
||||
totalResults: data.total_results,
|
||||
results: data.results
|
||||
.map((result) => mapPersonResult(result))
|
||||
.filter((item) => !item.adult),
|
||||
});
|
||||
});
|
||||
|
||||
export default discoverRoutes;
|
||||
|
||||
49
src/components/Discover/DiscoverPeople.tsx
Normal file
49
src/components/Discover/DiscoverPeople.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import type { PersonResult } from '../../../server/models/Search';
|
||||
import useDiscover from '../../hooks/useDiscover';
|
||||
import Error from '../../pages/_error';
|
||||
import Header from '../Common/Header';
|
||||
import ListView from '../Common/ListView';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
|
||||
const messages = defineMessages({
|
||||
popularpeople: 'Popular People',
|
||||
});
|
||||
|
||||
const DiscoverPeople: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
isLoadingInitialData,
|
||||
isEmpty,
|
||||
isLoadingMore,
|
||||
isReachingEnd,
|
||||
titles,
|
||||
fetchMore,
|
||||
error,
|
||||
} = useDiscover<PersonResult>('/api/v1/discover/people');
|
||||
|
||||
if (error) {
|
||||
return <Error statusCode={500} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={intl.formatMessage(messages.popularpeople)} />
|
||||
<div className="mt-1 mb-5">
|
||||
<Header>{intl.formatMessage(messages.popularpeople)}</Header>
|
||||
</div>
|
||||
<ListView
|
||||
items={titles}
|
||||
isEmpty={isEmpty}
|
||||
isLoading={
|
||||
isLoadingInitialData || (isLoadingMore && (titles?.length ?? 0) > 0)
|
||||
}
|
||||
isReachingEnd={isReachingEnd}
|
||||
onScrollBottom={fetchMore}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DiscoverPeople;
|
||||
@@ -25,6 +25,7 @@ const messages = defineMessages({
|
||||
noRequests: 'No requests.',
|
||||
upcoming: 'Upcoming Movies',
|
||||
trending: 'Trending',
|
||||
popularpeople: 'Popular People',
|
||||
});
|
||||
|
||||
const Discover: React.FC = () => {
|
||||
@@ -116,6 +117,12 @@ const Discover: React.FC = () => {
|
||||
linkUrl="/discover/tv/upcoming"
|
||||
/>
|
||||
<NetworkSlider />
|
||||
<MediaSlider
|
||||
sliderKey="popular-people"
|
||||
title={intl.formatMessage(messages.popularpeople)}
|
||||
url="/api/v1/discover/people"
|
||||
linkUrl="/discover/people"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"components.Discover.discovertv": "Popular Series",
|
||||
"components.Discover.noRequests": "No requests.",
|
||||
"components.Discover.popularmovies": "Popular Movies",
|
||||
"components.Discover.popularpeople": "Popular People",
|
||||
"components.Discover.populartv": "Popular Series",
|
||||
"components.Discover.recentlyAdded": "Recently Added",
|
||||
"components.Discover.recentrequests": "Recent Requests",
|
||||
|
||||
9
src/pages/discover/people/index.tsx
Normal file
9
src/pages/discover/people/index.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { NextPage } from 'next';
|
||||
import React from 'react';
|
||||
import DiscoverPeople from '../../../components/Discover/DiscoverPeople';
|
||||
|
||||
const DiscoverPeoplePage: NextPage = () => {
|
||||
return <DiscoverPeople />;
|
||||
};
|
||||
|
||||
export default DiscoverPeoplePage;
|
||||
Reference in New Issue
Block a user