api: fetch shows implemented
This commit is contained in:
56
apis/showApi.ts
Normal file
56
apis/showApi.ts
Normal file
@@ -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<Show[]> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
const { shows } = useShowContext();
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView>
|
||||
<View style={styles.mainContainer}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>FLTR</Text>
|
||||
</View>
|
||||
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 30 }}>
|
||||
{shows.map((show) => {
|
||||
const showLiveBadge = show.endDate === null;
|
||||
return (
|
||||
<ShowCard
|
||||
key={show.id}
|
||||
onPress={() => 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"]}
|
||||
imageUri={show.bannerUri || show.thumbnailUri}
|
||||
streamingServiceUri={show.streamingService}
|
||||
genres={show.genres}
|
||||
{...(showLiveBadge
|
||||
? {
|
||||
liveBadgeText: "LIVE",
|
||||
liveBadgeContainerStyle: styles.liveBadgeContainer,
|
||||
}
|
||||
: {})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { ShowProvider } from "@/contexts/ShowContext";
|
||||
import { Stack } from "expo-router";
|
||||
import "react-native-reanimated";
|
||||
|
||||
export default function RootLayout() {
|
||||
return (
|
||||
<ShowProvider>
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
@@ -12,5 +14,6 @@ export default function RootLayout() {
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</ShowProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 = ({
|
||||
<View style={styles.streamingServiceIcon}>
|
||||
<Image
|
||||
source={{
|
||||
uri: streamingServiceUri,
|
||||
uri: "https://play-lh.googleusercontent.com/e8u4F0ED6hDMzmjg5cV_C5Sxrzr3xECniwKCD2Q8QfUeVMVRLG41TrsnqroTE7uxk4E",
|
||||
}}
|
||||
style={[StyleSheet.absoluteFillObject, { borderRadius: 15 }]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{liveBadgeText && (
|
||||
<View style={liveBadgeContainerStyle}>
|
||||
<Text style={styles.liveBadgeText}>{liveBadgeText}</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.genreSection}>
|
||||
{genres.map((genre) => (
|
||||
<Text key={genre} style={styles.genreLabel}>
|
||||
@@ -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",
|
||||
},
|
||||
});
|
||||
|
||||
42
contexts/ShowContext.tsx
Normal file
42
contexts/ShowContext.tsx
Normal file
@@ -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<ShowContextType | null>(null);
|
||||
|
||||
export const ShowProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [shows, setShows] = useState<Show[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const data = await getShows();
|
||||
setShows(data);
|
||||
} catch {
|
||||
setError("Failed to fetch shows");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ShowContext.Provider value={{ shows, loading, error }}>
|
||||
{children}
|
||||
</ShowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useShowContext = () => {
|
||||
const ctx = useContext(ShowContext);
|
||||
if (!ctx)
|
||||
throw new Error("useShowContext must be used within a ShowProvider");
|
||||
return ctx;
|
||||
};
|
||||
Reference in New Issue
Block a user