diff --git a/apis/showApi.ts b/apis/showApi.ts new file mode 100644 index 0000000..f37cd6c --- /dev/null +++ b/apis/showApi.ts @@ -0,0 +1,56 @@ +export type RawShow = { + showId: number; + title: string; + description: string; + genre: string; + thumbnailUrl: string; + bannerUrl?: string; + concept: string; + streamingServices: string; + startDate?: string; + endDate?: string | null; +}; + +export type Show = { + id: number; + title: string; + description: string; + genres: string[]; + thumbnailUri: string; + bannerUri: string; + streamingService: string; + concept: string; + startDate?: string; + endDate?: string | null; +}; + +const API_URL = "http://45.157.177.99:8080/shows"; + +export async function getShows(): Promise { + try { + const response = await fetch(API_URL); + if (!response.ok) { + throw new Error("Network response was not ok"); + } + const data: unknown = await response.json(); + if (!Array.isArray(data)) { + console.warn("Expected array, got:", data); + return []; + } + return (data as RawShow[]).map((s) => ({ + id: s.showId, + title: s.title, + description: s.description, + genres: s.genre ? s.genre.split(",").map((g) => g.trim()) : [], + thumbnailUri: s.thumbnailUrl, + bannerUri: s.bannerUrl ?? "", + streamingService: s.streamingServices, + concept: s.concept, + startDate: s.startDate, + endDate: s.endDate ?? null, + })); + } catch (error) { + console.error("Fetch error:", error); + throw error; + } +} diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 84319d2..8bca53a 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,24 +1,44 @@ import styles from "@/app/styles/indexStyles"; import ShowCard from "@/components/ui/ShowCard"; +import { useShowContext } from "@/contexts/ShowContext"; import { router } from "expo-router"; import React from "react"; import { Text, View } from "react-native"; +import { + GestureHandlerRootView, + ScrollView, +} from "react-native-gesture-handler"; export default function HomeScreen() { - return ( - - - FLTR - + const { shows } = useShowContext(); - router.push("/showDetails")} - imageUri="https://streamcoimg-a.akamaihd.net/000/123/147/123147-Banner-L2-b81d3e6b4df34af2887f701eec382f87.jpg" - streamingServiceUri="https://play-lh.googleusercontent.com/e8u4F0ED6hDMzmjg5cV_C5Sxrzr3xECniwKCD2Q8QfUeVMVRLG41TrsnqroTE7uxk4E=w240-h480-rw" - liveBadgeText="LIVE" - liveBadgeContainerStyle={styles.liveBadgeContainer} - genres={["Reality", "Dating"]} - /> - + return ( + + + + FLTR + + + {shows.map((show) => { + const showLiveBadge = show.endDate === null; + return ( + router.push("/showDetails")} + imageUri={show.bannerUri || show.thumbnailUri} + streamingServiceUri={show.streamingService} + genres={show.genres} + {...(showLiveBadge + ? { + liveBadgeText: "LIVE", + liveBadgeContainerStyle: styles.liveBadgeContainer, + } + : {})} + /> + ); + })} + + + ); } diff --git a/app/_layout.tsx b/app/_layout.tsx index e82da96..51d7513 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,16 +1,19 @@ +import { ShowProvider } from "@/contexts/ShowContext"; import { Stack } from "expo-router"; import "react-native-reanimated"; export default function RootLayout() { return ( - - - - + + + + + + ); } diff --git a/components/ui/ShowCard.tsx b/components/ui/ShowCard.tsx index 3bf15a4..5743dbd 100644 --- a/components/ui/ShowCard.tsx +++ b/components/ui/ShowCard.tsx @@ -4,7 +4,7 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native"; type ShowCardProps = { imageUri: string; streamingServiceUri: string; - liveBadgeText: string; + liveBadgeText?: string; liveBadgeContainerStyle?: object; genres: string[]; onPress?: () => void; @@ -33,15 +33,16 @@ const ShowCard = ({ - - - {liveBadgeText} - + {liveBadgeText && ( + + {liveBadgeText} + + )} {genres.map((genre) => ( @@ -112,7 +113,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 10, borderRadius: 10, fontStyle: "italic", - backgroundColor: "rgba(255, 255, 255, 0.1)", + backgroundColor: "rgba(255, 255, 255, 1)", overflow: "hidden", }, }); diff --git a/contexts/ShowContext.tsx b/contexts/ShowContext.tsx new file mode 100644 index 0000000..d7ec9cc --- /dev/null +++ b/contexts/ShowContext.tsx @@ -0,0 +1,42 @@ +import { getShows, Show } from "@/apis/showApi"; +import { createContext, useContext, useEffect, useState } from "react"; + +type ShowContextType = { + shows: Show[]; + loading: boolean; + error: string | null; +}; + +const ShowContext = createContext(null); + +export const ShowProvider = ({ children }: { children: React.ReactNode }) => { + const [shows, setShows] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + (async () => { + try { + const data = await getShows(); + setShows(data); + } catch { + setError("Failed to fetch shows"); + } finally { + setLoading(false); + } + })(); + }, []); + + return ( + + {children} + + ); +}; + +export const useShowContext = () => { + const ctx = useContext(ShowContext); + if (!ctx) + throw new Error("useShowContext must be used within a ShowProvider"); + return ctx; +};