diff --git a/src/components/title/Reviews.tsx b/src/components/title/Reviews.tsx
index 0fe3e93..d0bebde 100644
--- a/src/components/title/Reviews.tsx
+++ b/src/components/title/Reviews.tsx
@@ -1,82 +1,127 @@
import { useRouter } from 'next/router';
import Link from 'next/link';
-import { Reviews } from 'src/interfaces/shared/title';
+import type { Reviews as TReviews } from 'src/interfaces/shared/title';
import { formatNumber } from 'src/utils/helpers';
import styles from 'src/styles/modules/components/title/reviews.module.scss';
type Props = {
- reviews: Reviews;
+ reviews: TReviews;
};
const Reviews = ({ reviews }: Props) => {
+ return (
+
+ Reviews
+
+
+
+
+ User Reviews
+ {reviews.featuredReviews ? (
+
+ {reviews.featuredReviews.map(featuredReview => (
+ -
+
+
+ {featuredReview.review.summary}
+
+
+
+
+
+ ))}
+
+ ) : (
+ No reviews yet.
+ )}
+
+
+ {reviews.ai?.summary && (
+
+ AI Summary
+
+
+ {reviews.ai.themes.map(theme => (
+ - {theme.text}
+ ))}
+
+
+ )}
+
+
+
+ );
+};
+
+export default Reviews;
+
+const RatingsDistribution = ({ ratings }: { ratings: Props['reviews']['ratingsDistribution'] }) => {
+ const maxRating = Math.max(...ratings.map(r => r.votes));
+
+ return (
+
+
Ratings Distribution
+ {ratings.length ? (
+
+ {ratings.map(rating => (
+ -
+
+ {rating.rating} ({formatNumber(rating.votes)})
+
+
+ ))}
+
+ ) : (
+
No ratings yet.
+ )}
+
+ );
+};
+
+const ReviewStats = ({ reviews }: { reviews: Props['reviews'] }) => {
const router = useRouter();
const { titleId } = router.query;
return (
-
- Reviews
-
- {reviews.featuredReview && (
-
-
-
- {reviews.featuredReview.review.summary}
-
-
-
-
-
- )}
-
-
-
+
);
};
-export default Reviews;
diff --git a/src/interfaces/misc/rawTitle.ts b/src/interfaces/misc/rawTitle.ts
index ffc4603..034aac9 100644
--- a/src/interfaces/misc/rawTitle.ts
+++ b/src/interfaces/misc/rawTitle.ts
@@ -2,7 +2,250 @@ export default interface RawTitle {
props: {
pageProps: {
aboveTheFoldData: {
+ canHaveEpisodes: boolean;
+ canRate: {
+ isRatable: boolean;
+ };
+ castPageTitle: {
+ edges: Array<{
+ node: {
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ };
+ }>;
+ };
+ certificate?: {
+ rating: string;
+ };
+ countriesOfOrigin?: {
+ countries: Array<{
+ id: string;
+ }>;
+ };
+ creatorsPageTitle: Array<{
+ credits: Array<{
+ name: {
+ nameText: {
+ text: string;
+ };
+ };
+ }>;
+ }>;
+ credits: {
+ total: number;
+ };
+ criticReviewsTotal: {
+ total: number;
+ };
+ directorsPageTitle: Array<{
+ credits: Array<{
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ }>;
+ }>;
+ engagementStatistics?: {
+ watchlistStatistics: {
+ displayableCount: {
+ text: string;
+ };
+ };
+ };
+ externalLinks: {
+ total: number;
+ };
+ featuredReviews: {
+ edges: Array<{
+ node: {
+ author: {
+ nickName: string;
+ };
+ authorRating?: number;
+ submissionDate: string;
+ summary: {
+ originalText: string;
+ };
+ text: {
+ originalText: {
+ plainText: string;
+ };
+ };
+ };
+ }>;
+ };
+ genres: {
+ genres: Array<{
+ id: string;
+ text: string;
+ }>;
+ };
id: string;
+ images: {
+ edges: Array<{
+ node: {
+ id: string;
+ };
+ }>;
+ total: number;
+ };
+ interests: {
+ edges: Array<{
+ node: {
+ id: string;
+ primaryText: {
+ text: string;
+ };
+ };
+ }>;
+ };
+ isAdult: boolean;
+ keywords: {
+ edges: Array<{
+ node: {
+ text: string;
+ };
+ }>;
+ total: number;
+ };
+ meta: {
+ canonicalId: string;
+ publicationStatus: string;
+ };
+ metacritic?: {
+ metascore: {
+ score: number;
+ };
+ };
+ meterRanking?: {
+ currentRank: number;
+ rankChange: {
+ changeDirection: string;
+ difference: number;
+ };
+ };
+ originalTitleText: {
+ text: string;
+ };
+ plot?: {
+ language?: {
+ id: string;
+ };
+ plotText?: {
+ plainText: string;
+ };
+ };
+ plotContributionLink: {
+ url: string;
+ };
+ primaryImage?: {
+ caption: {
+ plainText: string;
+ };
+ height: number;
+ id: string;
+ url: string;
+ width: number;
+ };
+ primaryVideos: {
+ edges: Array<{
+ node: {
+ contentType: {
+ displayName: {
+ value: string;
+ };
+ id: string;
+ };
+ createdDate: string;
+ description?: {
+ language: string;
+ value: string;
+ };
+ id: string;
+ isMature: boolean;
+ name: {
+ language: string;
+ value: string;
+ };
+ playbackURLs: Array<{
+ displayName: {
+ language: string;
+ value: string;
+ };
+ url: string;
+ videoDefinition: string;
+ videoMimeType?: string;
+ }>;
+ previewURLs: Array<{
+ displayName: {
+ language: string;
+ value: string;
+ };
+ url: string;
+ videoDefinition: string;
+ videoMimeType: string;
+ }>;
+ primaryTitle: {
+ id: string;
+ originalTitleText: {
+ text: string;
+ };
+ releaseYear: {
+ year: number;
+ };
+ titleText: {
+ text: string;
+ };
+ };
+ recommendedTimedTextTrack: null;
+ runtime: {
+ value: number;
+ };
+ thumbnail: {
+ height: number;
+ url: string;
+ width: number;
+ };
+ timedTextTracks: Array;
+ };
+ }>;
+ };
+ principalCredits: Array<{
+ category: {
+ id: string;
+ text: string;
+ };
+ credits: Array<{
+ attributes?: Array<{
+ text: string;
+ }>;
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ }>;
+ totalCredits: number;
+ }>;
+ production: {
+ edges: Array<{
+ node: {
+ company: {
+ companyText: {
+ text: string;
+ };
+ id: string;
+ };
+ };
+ }>;
+ };
productionStatus: {
currentProductionStage: {
id: string;
@@ -19,7 +262,33 @@ export default interface RawTitle {
unrestrictedTotal: number;
};
} | null;
- canHaveEpisodes: boolean;
+ ratingsSummary: {
+ aggregateRating?: number;
+ voteCount: number;
+ };
+ releaseDate: {
+ country: {
+ text: string;
+ };
+ day: number;
+ month: number;
+ year: number;
+ };
+ releaseYear: {
+ endYear: any;
+ year: number;
+ };
+ reviews: {
+ total: number;
+ };
+ runtime?: {
+ displayableProperty: {
+ value: {
+ plainText: string;
+ };
+ };
+ seconds: number;
+ };
series?: {
episodeNumber: {
episodeNumber: number;
@@ -50,374 +319,93 @@ export default interface RawTitle {
};
};
};
+ subNavCredits: {
+ total: number;
+ };
+ subNavFaqs: {
+ total: number;
+ };
+ subNavReviews: {
+ total: number;
+ };
+ subNavTopQuestions: {
+ total: number;
+ };
+ subNavTrivia: {
+ total: number;
+ };
+ titleGenres: {
+ genres: Array<{
+ genre: {
+ text: string;
+ };
+ }>;
+ };
titleText: {
text: string;
};
titleType: {
- text: string;
+ canHaveEpisodes: boolean;
+ categories: Array<{
+ value: string;
+ }>;
+ displayableProperty: {
+ value: {
+ plainText: string;
+ };
+ };
id: string;
- isSeries: boolean;
isEpisode: boolean;
- };
- originalTitleText: {
+ isSeries: boolean;
text: string;
};
- certificate?: {
- rating: string;
- };
- releaseYear?: {
- year: number;
- endYear: any;
- };
- releaseDate?: {
- day: number;
- month: number;
- year: number;
- };
- runtime?: {
- seconds: number;
- };
- canRate: {
- isRatable: boolean;
- };
- ratingsSummary: {
- aggregateRating?: number;
- voteCount: number;
- };
- meterRanking?: {
- currentRank: number;
- rankChange: {
- changeDirection: string;
- difference: number;
- };
- };
- primaryImage?: {
- id: string;
- width: number;
- height: number;
- url: string;
- caption: {
- plainText: string;
- };
- };
- images: {
- total: number;
- };
- videos: {
- total: number;
- };
- primaryVideos: {
- edges: Array<{
- node: {
- id: string;
- isMature: boolean;
- contentType: {
- id: string;
- displayName: {
- value: string;
- };
- };
- thumbnail: {
- url: string;
- height: number;
- width: number;
- };
- runtime: {
- value: number;
- };
- description?: {
- value: string;
- language: string;
- };
- name: {
- value: string;
- language: string;
- };
- playbackURLs: Array<{
- displayName: {
- value: string;
- language: string;
- };
- mimeType?: string;
- url: string;
- }>;
- previewURLs: Array<{
- displayName: {
- value: string;
- language: string;
- };
- mimeType: string;
- url: string;
- }>;
- };
- }>;
- };
- externalLinks: {
- total: number;
- };
- metacritic?: {
- metascore: {
- score: number;
- };
- };
- keywords: {
- total: number;
- edges: Array<{
- node: {
- text: string;
- };
- }>;
- };
- genres: {
- genres: Array<{
- text: string;
- id: string;
- }>;
- };
- plot?: {
- plotText?: {
- plainText: string;
- };
- language?: {
- id: string;
- };
- };
- plotContributionLink: {
- url: string;
- };
- credits: {
- total: number;
- };
- principalCredits: Array<{
- totalCredits: number;
- category: {
- text: string;
- id: string;
- };
- credits: Array<{
- name: {
- nameText: {
- text: string;
- };
- id: string;
- };
- attributes?: Array<{
- text: string;
- }>;
- }>;
- }>;
- reviews: {
- total: number;
- };
- criticReviewsTotal: {
- total: number;
- };
triviaTotal: {
total: number;
};
- meta: {
- canonicalId: string;
- publicationStatus: string;
- };
- castPageTitle: {
- edges: Array<{
- node: {
- name: {
- nameText: {
- text: string;
- };
- };
- };
- }>;
- };
- creatorsPageTitle: Array<{
- credits: Array<{
- name: {
- nameText: {
- text: string;
- };
- };
- }>;
- }>;
- directorsPageTitle: Array<{
- credits: Array<{
- name: {
- nameText: {
- text: string;
- };
- };
- }>;
- }>;
- countriesOfOrigin?: {
- countries: Array<{
- id: string;
- }>;
- };
- production: {
- edges: Array<{
- node: {
- company: {
- id: string;
- companyText: {
- text: string;
- };
- };
- };
- }>;
- };
- featuredReviews: {
- edges: Array<{
- node: {
- author: {
- nickName: string;
- };
- summary: {
- originalText: string;
- };
- text: {
- originalText: {
- plainText: string;
- };
- };
- authorRating: number;
- submissionDate: string;
- };
- }>;
- };
- };
- mainColumnData: {
- id: string;
- wins: {
- total: number;
- };
- nominationsExcludeWins: {
- total: number;
- };
- prestigiousAwardSummary?: {
- nominations: number;
- wins: number;
- award: {
- text: string;
- id: string;
- event: {
- id: string;
- };
- };
- };
- ratingsSummary: {
- topRanking?: {
- id: string;
- text: {
- value: string;
- };
- rank: number;
- };
- };
- episodes?: {
- episodes: {
- total: number;
- };
- seasons: Array<{
- number: number;
- }>;
- years: Array<{
- year: number;
- }>;
- totalEpisodes: {
- total: number;
- };
- topRated: {
- edges: Array<{
- node: {
- ratingsSummary: {
- aggregateRating: number;
- };
- };
- }>;
- };
- };
videos: {
total: number;
};
- videoStrip: {
- edges: Array<{
- node: {
- id: string;
- contentType: {
- displayName: {
- value: string;
- };
- };
- name: {
- value: string;
- };
- runtime: {
- value: number;
- };
- thumbnail: {
- height: number;
- url: string;
- width: number;
- };
- };
- }>;
- };
- titleMainImages: {
- total: number;
- edges: Array<{
- node: {
- id: string;
- url: string;
- caption: {
- plainText: string;
- };
- height: number;
- width: number;
- };
- }>;
- };
- productionStatus: {
- currentProductionStage: {
- id: string;
- text: string;
+ };
+ mainColumnData: {
+ aggregateRatingsBreakdown: {
+ histogram: {
+ histogramValues: Array<{
+ rating: number;
+ voteCount: number;
+ }>;
};
- productionStatusHistory?: Array<{
- status: {
- id: string;
+ };
+ akas: {
+ edges: Array<{
+ node: {
text: string;
};
}>;
- restriction?: {
- restrictionReason: Array;
- };
};
- primaryImage?: {
- id: string;
+ alternateVersions: {
+ edges: Array<{
+ node: {
+ text: {
+ plaidHtml: string;
+ };
+ };
+ }>;
+ total: number;
};
- imageUploadLink?: {
- url: string;
- };
- titleType: {
- id: string;
- canHaveEpisodes: boolean;
+ canHaveEpisodes: boolean;
+ canRate: {
+ isRatable: boolean;
};
cast: {
edges: Array<{
node: {
- name: {
- id: string;
- nameText: {
- text: string;
- };
- primaryImage?: {
- url: string;
- width: number;
- height: number;
- };
- };
attributes?: Array<{
text: string;
}>;
+ category: {
+ id: string;
+ text: string;
+ };
characters?: Array<{
name: string;
}>;
@@ -428,184 +416,48 @@ export default interface RawTitle {
endYear: number;
};
};
- };
- }>;
- };
- creators: Array<{
- totalCredits: number;
- category: {
- text: string;
- };
- credits: Array<{
- name: {
- id: string;
- nameText: {
- text: string;
- };
- };
- attributes: any;
- }>;
- }>;
- directors: Array<{
- totalCredits: number;
- category: {
- text: string;
- };
- credits: Array<{
- name: {
- id: string;
- nameText: {
- text: string;
- };
- };
- attributes: any;
- }>;
- }>;
- writers: Array<{
- totalCredits: number;
- category: {
- text: string;
- };
- credits: Array<{
- name: {
- id: string;
- nameText: {
- text: string;
- };
- };
- attributes?: Array<{
- text: string;
- }>;
- }>;
- }>;
- isAdult: boolean;
- moreLikeThisTitles: {
- edges: Array<{
- node: {
- id: string;
- titleText: {
- text: string;
- };
- titleType: {
+ name: {
id: string;
- text: string;
+ nameText: {
+ text: string;
+ };
+ primaryImage?: {
+ height: number;
+ url: string;
+ width: number;
+ };
};
- originalTitleText: {
- text: string;
- };
- primaryImage?: {
- id: string;
- width: number;
- height: number;
- url: string;
- };
- releaseYear?: {
- year: number;
- endYear?: number;
- };
- ratingsSummary: {
- aggregateRating?: number;
- voteCount: number;
- };
- runtime?: {
- seconds: number;
- };
- certificate?: {
- rating: string;
- };
- canRate: {
- isRatable: boolean;
- };
- titleGenres?: {
- genres: Array<{
- genre: {
- text: string;
- };
- }>;
- };
- canHaveEpisodes: boolean;
};
}>;
- };
- triviaTotal: {
total: number;
};
- trivia: {
- edges: Array<{
- node: {
- text: {
- plaidHtml: string;
- };
- trademark: any;
- relatedNames: any;
- };
- }>;
- };
- goofsTotal: {
+ companies: {
total: number;
};
- goofs: {
- edges: Array<{
- node: {
- text: {
- plaidHtml: string;
- };
- };
- }>;
- };
- quotesTotal: {
- total: number;
- };
- quotes: {
- edges: Array<{
- node: {
- lines: Array<{
- characters?: Array<{
- character: string;
- name?: {
- id: string;
- };
- }>;
- text: string;
- stageDirection?: string;
- }>;
- };
- }>;
- };
- crazyCredits: {
- edges: Array<{
- node: {
- text: {
- plaidHtml: string;
- };
- };
- }>;
- };
- alternateVersions: {
- total: number;
- edges: Array<{
- node: {
- text: {
- plaidHtml: string;
- };
- };
- }>;
- };
connections: {
edges: Array<{
node: {
associatedTitle: {
id: string;
+ originalTitleText: {
+ text: string;
+ };
releaseYear: {
year: number;
};
+ series?: {
+ series: {
+ originalTitleText: {
+ text: string;
+ };
+ titleText: {
+ text: string;
+ };
+ };
+ };
titleText: {
text: string;
};
- originalTitleText: {
- text: string;
- };
- series: any;
};
category: {
text: string;
@@ -613,195 +465,6 @@ export default interface RawTitle {
};
}>;
};
- soundtrack: {
- edges: Array<{
- node: {
- text: string;
- comments?: Array<{
- plaidHtml: string;
- }>;
- };
- }>;
- };
- titleText: {
- text: string;
- };
- originalTitleText: {
- text: string;
- };
- releaseYear?: {
- year: number;
- };
- reviews: {
- total: number;
- };
- featuredReviews: {
- edges: Array<{
- node: {
- id: string;
- author: {
- nickName: string;
- userId: string;
- };
- summary: {
- originalText: string;
- };
- text: {
- originalText: {
- plaidHtml: string;
- };
- };
- authorRating: number;
- submissionDate: string;
- helpfulness: {
- upVotes: number;
- downVotes: number;
- };
- };
- }>;
- };
- canRate: {
- isRatable: boolean;
- };
- iframeAddReviewLink: {
- url: string;
- };
- faqsTotal: {
- total: number;
- };
- faqs: {
- edges: Array<{
- node: {
- id: string;
- question: {
- plainText: string;
- };
- };
- }>;
- };
- releaseDate?: {
- day: number;
- month: number;
- year: number;
- country: {
- id: string;
- text: string;
- };
- };
- countriesOfOrigin?: {
- countries: Array<{
- id: string;
- text: string;
- }>;
- };
- detailsExternalLinks: {
- edges: Array<{
- node: {
- url: string;
- label: string;
- externalLinkRegion?: {
- text: string;
- };
- };
- }>;
- total: number;
- };
- spokenLanguages: {
- spokenLanguages: Array<{
- id: string;
- text: string;
- }>;
- };
- akas: {
- edges: Array<{
- node: {
- text: string;
- };
- }>;
- };
- filmingLocations: {
- edges: Array<{
- node: {
- text: string;
- };
- }>;
- total: number;
- };
- production: {
- edges: Array<{
- node: {
- company: {
- id: string;
- companyText: {
- text: string;
- };
- };
- };
- }>;
- };
- companies: {
- total: number;
- };
- productionBudget?: {
- budget: {
- amount: number;
- currency: string;
- };
- };
- lifetimeGross?: {
- total: {
- amount: number;
- currency: string;
- };
- };
- openingWeekendGross?: {
- gross: {
- total: {
- amount: number;
- currency: string;
- };
- };
- weekendEndDate: string;
- };
- worldwideGross?: {
- total: {
- amount: number;
- currency: string;
- };
- };
- technicalSpecifications: {
- soundMixes: {
- items: Array<{
- id: string;
- text: string;
- attributes: Array;
- }>;
- };
- aspectRatios: {
- items: Array<{
- aspectRatio: string;
- attributes: Array;
- }>;
- };
- colorations: {
- items: Array<{
- conceptId: string;
- text: string;
- attributes: Array;
- }>;
- };
- };
- runtime?: {
- seconds: number;
- };
- series?: {
- series: {
- runtime?: {
- seconds: number;
- };
- };
- };
- canHaveEpisodes: boolean;
contributionQuestions: {
contributionLink: {
url: string;
@@ -828,7 +491,479 @@ export default interface RawTitle {
};
}>;
};
+ countriesDetails: {
+ countries: Array<{
+ id: string;
+ text: string;
+ }>;
+ };
+ crazyCredits: {
+ edges: Array<{
+ node: {
+ text: {
+ plaidHtml: string;
+ };
+ };
+ }>;
+ };
+ creators: Array<{
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ attributes: any;
+ }>;
+ detailsExternalLinks: {
+ edges: Array<{
+ node: {
+ externalLinkRegion?: { text: string };
+ label: string;
+ url: string;
+ };
+ }>;
+ total: number;
+ };
+ directors: Array<{
+ category: {
+ id: string;
+ text: string;
+ };
+ credits: Array<{
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ attributes?: Array<{ text: string }>;
+ }>;
+ totalCredits: number;
+ }>;
+ episodes?: {
+ episodes: {
+ total: number;
+ };
+ seasons: Array<{
+ number: number;
+ }>;
+ years: Array<{
+ year: number;
+ }>;
+ totalEpisodes: {
+ total: number;
+ };
+ topRated: {
+ edges: Array<{
+ node: {
+ ratingsSummary: {
+ aggregateRating: number;
+ };
+ };
+ }>;
+ };
+ };
+ faqs: {
+ edges: Array<{
+ node: {
+ id: string;
+ question: {
+ plainText: string;
+ };
+ };
+ }>;
+ total: number;
+ };
+ featuredReviews: {
+ edges: Array<{
+ node: {
+ author: {
+ userId: string;
+ username: {
+ text: string;
+ };
+ };
+ authorRating?: number;
+ id: string;
+ summary: {
+ originalText: string;
+ };
+ text: {
+ originalText: {
+ plaidHtml: string;
+ };
+ };
+ };
+ }>;
+ };
+ filmingLocations: {
+ edges: Array<{
+ node: {
+ attributes: Array;
+ location: string;
+ text: string;
+ };
+ }>;
+ total: number;
+ };
+ goofs: {
+ edges: Array<{
+ node: {
+ text: {
+ plaidHtml: string;
+ };
+ };
+ }>;
+ };
+ goofsTotal: {
+ total: number;
+ };
+ id: string;
+ inIframeAddLink: {
+ url: string;
+ };
+ isAdult: boolean;
+ lifetimeGross?: {
+ total: {
+ amount: number;
+ currency: string;
+ };
+ };
+ moreLikeThisTitles: {
+ edges: Array<{
+ node: {
+ canHaveEpisodes: boolean;
+ canRate: {
+ isRatable: boolean;
+ };
+ certificate?: {
+ rating: string;
+ };
+ id: string;
+ originalTitleText: {
+ text: string;
+ };
+ primaryImage?: {
+ caption?: {
+ plainText: string;
+ };
+ height: number;
+ id: string;
+ url: string;
+ width: number;
+ };
+ ratingsSummary: {
+ aggregateRating?: number;
+ voteCount: number;
+ };
+ releaseYear?: {
+ endYear?: number;
+ year: number;
+ };
+ runtime?: {
+ seconds: number;
+ };
+ titleGenres?: {
+ genres: Array<{
+ genre: {
+ text: string;
+ };
+ }>;
+ };
+ titleText: {
+ text: string;
+ };
+ titleType: {
+ canHaveEpisodes: boolean;
+ displayableProperty: {
+ value: {
+ plainText: string;
+ };
+ };
+ id: string;
+ text: string;
+ };
+ };
+ }>;
+ };
+ nominationsExcludeWins: {
+ total: number;
+ };
+ notInIframeAddLink: {
+ url: string;
+ };
+ openingWeekendGross?: {
+ gross: {
+ total: {
+ amount: number;
+ currency: string;
+ };
+ };
+ weekendEndDate: string;
+ };
+ originalTitleText: {
+ text: string;
+ };
+ prestigiousAwardSummary?: {
+ award: {
+ event: {
+ id: string;
+ };
+ id: string;
+ text: string;
+ };
+ nominations: number;
+ wins: number;
+ };
+ primaryImage?: {
+ caption: {
+ plainText: string;
+ };
+ height: number;
+ id: string;
+ url: string;
+ width: number;
+ };
+ production: {
+ edges: Array<{
+ node: {
+ company: {
+ companyText: {
+ text: string;
+ };
+ id: string;
+ };
+ };
+ }>;
+ };
+ productionBudget?: {
+ budget: {
+ amount: number;
+ currency: string;
+ };
+ };
+ productionStatus: {
+ currentProductionStage: {
+ id: string;
+ text: string;
+ };
+ productionStatusHistory?: Array<{
+ status: {
+ id: string;
+ text: string;
+ };
+ }>;
+ restriction?: {
+ restrictionReason: Array;
+ };
+ };
+ quotes: {
+ edges: Array<{
+ node: {
+ lines: Array<{
+ characters?: Array<{
+ character: string;
+ name?: {
+ id: string;
+ };
+ }>;
+ stageDirection?: string;
+ text: string;
+ }>;
+ };
+ }>;
+ };
+ quotesTotal: {
+ total: number;
+ };
+ ratingsSummary: {
+ aggregateRating: number;
+ notificationText?: string;
+ topRanking?: {
+ id: string;
+ rank: number;
+ text: {
+ value: string;
+ };
+ };
+ voteCount: number;
+ };
+ releaseDate?: {
+ country: {
+ id: string;
+ text: string;
+ };
+ day: number;
+ month: number;
+ year: number;
+ };
+ reviews: {
+ total: number;
+ };
+ reviewSummary?: {
+ overall: {
+ medium: {
+ value: {
+ plaidHtml: string;
+ };
+ };
+ };
+ themes: Array<{
+ label: {
+ value: string;
+ };
+ sentiment: string;
+ themeId: string;
+ }>;
+ };
+ runtime: {
+ seconds: number;
+ };
+ series?: {
+ series: {
+ runtime?: {
+ seconds: number;
+ };
+ };
+ };
+ soundtrack: {
+ edges: Array<{
+ node: {
+ comments?: Array<{
+ plaidHtml: string;
+ }>;
+ text: string;
+ };
+ }>;
+ };
+ spokenLanguages: {
+ spokenLanguages: Array<{
+ id: string;
+ text: string;
+ }>;
+ };
+ technicalSpecifications: {
+ aspectRatios: {
+ items: Array<{
+ aspectRatio: string;
+ attributes: Array;
+ }>;
+ };
+ colorations: {
+ items: Array<{
+ attributes: Array;
+ conceptId: string;
+ text: string;
+ }>;
+ };
+ soundMixes: {
+ items: Array<{
+ attributes: Array;
+ id: string;
+ text: string;
+ }>;
+ };
+ };
+ titleMainImages: {
+ edges: Array<{
+ node: {
+ caption: {
+ plainText: string;
+ };
+ height: number;
+ id: string;
+ url: string;
+ width: number;
+ };
+ }>;
+ total: number;
+ };
+ titleText: {
+ text: string;
+ };
+ titleType: {
+ canHaveEpisodes: boolean;
+ id: string;
+ };
+ topQuestions: {
+ edges: Array<{
+ node: {
+ attributeId: string;
+ question: {
+ plainText: string;
+ };
+ };
+ }>;
+ total: number;
+ };
+ trivia: {
+ edges: Array<{
+ node: {
+ relatedNames: any;
+ text: {
+ plaidHtml: string;
+ };
+ trademark: any;
+ };
+ }>;
+ };
+ triviaTotal: {
+ total: number;
+ };
+ videos: {
+ total: number;
+ };
+ videoStrip: {
+ edges: Array<{
+ node: {
+ contentType: {
+ displayName: {
+ value: string;
+ };
+ };
+ id: string;
+ name: {
+ value: string;
+ };
+ runtime: {
+ value: number;
+ };
+ thumbnail: {
+ height: number;
+ url: string;
+ width: number;
+ };
+ };
+ }>;
+ };
+ wins: {
+ total: number;
+ };
+ worldwideGross?: {
+ total: {
+ amount: number;
+ currency: string;
+ };
+ };
+ writers: Array<{
+ category: {
+ id: string;
+ text: string;
+ };
+ credits: Array<{
+ name: {
+ id: string;
+ nameText: {
+ text: string;
+ };
+ };
+ attributes?: Array<{ text: string }>;
+ }>;
+ totalCredits: number;
+ }>;
};
+ tconst: string;
};
};
}
diff --git a/src/styles/modules/components/title/reviews.module.scss b/src/styles/modules/components/title/reviews.module.scss
index 685748a..22b58c2 100644
--- a/src/styles/modules/components/title/reviews.module.scss
+++ b/src/styles/modules/components/title/reviews.module.scss
@@ -1,26 +1,94 @@
.reviews {
display: grid;
gap: var(--comp-whitespace);
+}
- &__reviewContainer {
- // background-color: antiquewhite;
+.ratingsDistribution {
+ overflow: hidden;
+
+ ul {
+ list-style: none;
+ display: flex;
+ gap: var(--spacer-2);
+ overflow-x: auto;
+ padding-block: var(--spacer-1);
}
- &__stats {
+ li {
+ text-align: center;
display: flex;
+ flex-direction: column;
+ height: 5em;
+ align-items: center;
+ flex-shrink: 0;
+
+ &::before {
+ display: block;
+ content: '';
+
+ height: var(--bar-height);
+ margin-top: auto;
+ background-color: var(--clr-fill);
+ width: var(--spacer-6);
+ border-radius: var(--spacer-0);
+ }
+
+ span {
+ font-weight: var(--fw-bold);
+
+ > span {
+ font-weight: initial;
+ font-size: 0.9em;
+ color: var(--clr-text-muted);
+ }
+ }
+ }
+}
+
+.reviewAi {
+ summary {
+ cursor: pointer;
+ }
+ p {
+ padding-block: var(--spacer-2);
+ }
+ ul {
+ list-style: none;
+ display: flex;
+ gap: var(--spacer-1);
flex-wrap: wrap;
- gap: var(--spacer-2);
+
+ li {
+ padding: var(--spacer-1);
+ background-color: var(--clr-bg-muted);
+ border-radius: var(--spacer-0);
+ }
+ }
+}
+
+.reviewStats {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--spacer-2);
+}
+
+.userReviews {
+
+ &__list {
+ padding-block-start: var(--spacer-1);
+ display: grid;
+ gap: var(--spacer-1);
+ list-style: none;
}
}
.review {
&__summary {
- font-size: calc(var(--fs-5) * 1.1);
cursor: pointer;
}
&__text,
&__metadata {
- padding-top: var(--spacer-2);
+ padding-top: var(--spacer-1);
}
}
diff --git a/src/utils/cleaners/title.ts b/src/utils/cleaners/title.ts
index 7902925..2e95661 100644
--- a/src/utils/cleaners/title.ts
+++ b/src/utils/cleaners/title.ts
@@ -12,6 +12,7 @@ const cleanTitle = (rawData: RawTitle) => {
titleId: main.id,
basic: {
id: main.id,
+ isAdult: main.isAdult,
title: main.titleText.text,
// ...(main.originalTitleText.text.toLowerCase() !==
// main.titleText.text.toLowerCase() && {
@@ -50,6 +51,10 @@ const cleanTitle = (rawData: RawTitle) => {
id: genre.id,
text: genre.text,
})),
+ interests: main.interests.edges.map(interest => ({
+ id: interest.node.id,
+ text: interest.node.primaryText.text,
+ })),
plot: main.plot?.plotText?.plainText || null,
primaryCrew: main.principalCredits.map(type => ({
type: { category: type.category.text, id: type.category.id },
@@ -84,7 +89,7 @@ const cleanTitle = (rawData: RawTitle) => {
caption: main.primaryVideos.edges[0].node.description?.value ?? null,
urls: main.primaryVideos.edges[0].node.playbackURLs.map(url => ({
resolution: url.displayName.value,
- mimeType: url.mimeType ?? null,
+ mimeType: url.videoMimeType ?? null,
url: url.url,
})),
},
@@ -122,6 +127,9 @@ const cleanTitle = (rawData: RawTitle) => {
}),
topRating: misc.ratingsSummary.topRanking?.rank || null,
},
+ watchlist: {
+ text: main.engagementStatistics?.watchlistStatistics.displayableCount.text || null,
+ },
meta: {
// for tv episode
...(main.series && {
@@ -208,25 +216,35 @@ const cleanTitle = (rawData: RawTitle) => {
metacriticScore: main.metacritic?.metascore.score || null,
numCriticReviews: main.criticReviewsTotal.total,
numUserReviews: misc.reviews.total,
- ...(misc.featuredReviews.edges.length && {
- featuredReview: {
- id: misc.featuredReviews.edges[0].node.id,
- reviewer: {
- id: misc.featuredReviews.edges[0].node.author.userId,
- name: misc.featuredReviews.edges[0].node.author.nickName,
- },
- rating: misc.featuredReviews.edges[0].node.authorRating,
- date: formatDate(misc.featuredReviews.edges[0].node.submissionDate),
- votes: {
- up: misc.featuredReviews.edges[0].node.helpfulness.upVotes,
- down: misc.featuredReviews.edges[0].node.helpfulness.downVotes,
- },
- review: {
- summary: misc.featuredReviews.edges[0].node.summary.originalText,
- html: misc.featuredReviews.edges[0].node.text.originalText.plaidHtml,
- },
+ ratingsDistribution:
+ misc.aggregateRatingsBreakdown.histogram?.histogramValues.map(v => ({
+ rating: v.rating,
+ votes: v.voteCount,
+ })) || [],
+ ...(misc.reviewSummary && {
+ ai: {
+ summary: misc.reviewSummary.overall.medium.value.plaidHtml,
+ themes: misc.reviewSummary.themes.map(t => ({
+ text: t.label.value,
+ id: t.themeId,
+ sentiment: t.sentiment as 'POSITIVE' | 'NEGATIVE',
+ })),
},
}),
+ ...(misc.featuredReviews.edges.length && {
+ featuredReviews: misc.featuredReviews.edges.map(featuredReview => ({
+ id: featuredReview.node.id,
+ reviewer: {
+ id: featuredReview.node.author.userId,
+ name: featuredReview.node.author.username.text,
+ },
+ rating: featuredReview.node.authorRating,
+ review: {
+ summary: featuredReview.node.summary.originalText,
+ html: featuredReview.node.text.originalText.plaidHtml,
+ },
+ })),
+ }),
},
details: {
...(misc.releaseDate && {
@@ -242,8 +260,8 @@ const cleanTitle = (rawData: RawTitle) => {
},
},
}),
- ...(misc.countriesOfOrigin && {
- countriesOfOrigin: misc.countriesOfOrigin.countries.map(country => ({
+ ...(misc.countriesDetails && {
+ countriesOfOrigin: misc.countriesDetails.countries.map(country => ({
id: country.id,
text: country.text,
})),
@@ -353,6 +371,10 @@ const cleanTitle = (rawData: RawTitle) => {
},
genres: title.node.titleGenres?.genres.map(genre => genre.genre.text) ?? null,
})),
+ faqs: {
+ questions: misc.faqs.edges.map(q => ({ question: q.node.question, id: q.node.id })),
+ total: misc.faqs.total,
+ },
};
return cleanData;