diff --git a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx index 3f6daae9..25fc8cb8 100644 --- a/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx +++ b/app/(auth)/(tabs)/(home,libraries,search,favorites)/jellyseerr/page.tsx @@ -28,6 +28,7 @@ import { TvDetails } from "@/utils/jellyseerr/server/models/Tv"; import JellyseerrSeasons from "@/components/series/JellyseerrSeasons"; import { JellyserrRatings } from "@/components/Ratings"; import MediaRequest from "@/utils/jellyseerr/server/entity/MediaRequest"; +import DetailFacts from "@/components/jellyseerr/DetailFacts"; const Page: React.FC = () => { const insets = useSafeAreaInsets(); @@ -221,6 +222,10 @@ const Page: React.FC = () => { refetch={refetch} /> )} + diff --git a/bun.lockb b/bun.lockb index cdb35dc5..bc0866e3 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/jellyseerr/DetailFacts.tsx b/components/jellyseerr/DetailFacts.tsx new file mode 100644 index 00000000..aa0e7885 --- /dev/null +++ b/components/jellyseerr/DetailFacts.tsx @@ -0,0 +1,167 @@ +import {View, ViewProps} from "react-native"; +import {MovieDetails} from "@/utils/jellyseerr/server/models/Movie"; +import {TvDetails} from "@/utils/jellyseerr/server/models/Tv"; +import {Text} from "@/components/common/Text"; +import {useMemo} from "react"; +import {useJellyseerr} from "@/hooks/useJellyseerr"; +import {uniqBy} from "lodash"; +import {TmdbRelease} from "@/utils/jellyseerr/server/api/themoviedb/interfaces"; +import {Ionicons, MaterialCommunityIcons} from "@expo/vector-icons"; +import CountryFlag from "react-native-country-flag"; +import {ANIME_KEYWORD_ID} from "@/utils/jellyseerr/server/api/themoviedb/constants"; + +interface Release { + certification: string; + iso_639_1?: string; + note?: string; + release_date: string; + type: number; +} + +const dateOpts: Intl.DateTimeFormatOptions = { + year: 'numeric', + month: 'long', + day: 'numeric', +} + +const Facts: React.FC<{title: string, facts?: string[] | React.ReactNode[]} & ViewProps> = ({title, facts, ...props}) => ( + facts && facts?.length > 0 && ( + + {title} + + + {facts.map((f, idx) => + typeof f === "string" ? {f} : f + )} + + + ) +) + +const Fact: React.FC<{title: string, fact?: string | null} & ViewProps> = ({title, fact, ...props}) => ( + fact && +) + +const DetailFacts: React.FC<{ details?: MovieDetails | TvDetails } & ViewProps> = ({ + details, + className, + ...props +}) => { + const {jellyseerrUser} = useJellyseerr(); + + const locale = useMemo(() => { + return jellyseerrUser?.settings?.locale || 'en' + }, [jellyseerrUser]); + + const region = useMemo( + () => jellyseerrUser?.settings?.region || 'US', + [jellyseerrUser] + ); + + const releases = useMemo( + () => (details as MovieDetails)?.releases?.results.find((r: TmdbRelease) => r.iso_3166_1 === region)?.release_dates as TmdbRelease['release_dates'], + [details] + ); + + // Release date types: + // 1. Premiere + // 2. Theatrical (limited) + // 3. Theatrical + // 4. Digital + // 5. Physical + // 6. TV + const filteredReleases = useMemo( + () => uniqBy(releases?.filter((r: Release) => r.type > 2 && r.type < 6), 'type'), + [releases] + ); + + const firstAirDate = useMemo(() => { + const firstAirDate = (details as TvDetails)?.firstAirDate + if (firstAirDate) { + return new Date(firstAirDate).toLocaleDateString(`${locale}-${region}`, dateOpts) + } + }, [details]); + + const nextAirDate = useMemo(() => { + const firstAirDate = (details as TvDetails)?.firstAirDate + const nextAirDate = (details as TvDetails)?.nextEpisodeToAir?.airDate + if (nextAirDate && firstAirDate !== nextAirDate) { + return new Date(nextAirDate).toLocaleDateString(`${locale}-${region}`, dateOpts) + } + }, [details]); + + const revenue = useMemo( + () => (details as MovieDetails)?.revenue + ?.toLocaleString?.(`${locale}-${region}`, {style: 'currency', currency: "USD"}), + [details] + ); + + const budget = useMemo( + () => (details as MovieDetails)?.budget + ?.toLocaleString?.(`${locale}-${region}`, {style: 'currency', currency: "USD"}), + [details] + ); + + const streamingProviders = useMemo( + () => details?.watchProviders?.find((provider) => provider.iso_3166_1 === region)?.flatrate, + [details] + ); + + const networks = useMemo( + () => (details as TvDetails)?.networks, + [details] + ); + + const spokenLanguage = useMemo( + () => details?.spokenLanguages.find((lng) => lng.iso_639_1 === details.originalLanguage)?.name, + [details] + ); + + return ( + details && + Details + + + + {details.keywords.some((keyword) => keyword.id === ANIME_KEYWORD_ID) && ( + + )} + + + {r.type === 3 ? ( + // Theatrical + + ) : r.type === 4 ? ( + // Digital + + ) : ( + // Physical + + )} + {new Date(r.release_date).toLocaleDateString(`${locale}-${region}`, dateOpts)} + + )} + /> + + + + + + + + + {n.name} + + )}/> + n.name)}/> + n.name)}/> + s.name)}/> + + + ) +} + +export default DetailFacts; \ No newline at end of file diff --git a/package.json b/package.json index 1284adac..b0a0ce75 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "react-native-bottom-tabs": "0.7.1", "react-native-circular-progress": "^1.4.1", "react-native-compressor": "^1.9.0", + "react-native-country-flag": "^2.0.2", "react-native-device-info": "^14.0.1", "react-native-edge-to-edge": "^1.1.3", "react-native-gesture-handler": "~2.16.1",