update: gemini fixes
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { AutoCompleteItem } from "@/apis/autoCompleteApi";
|
||||
import { getSearchResults, SearchResultItem } from "@/apis/searchApi";
|
||||
import { SearchResultItem } from "@/apis/searchApi";
|
||||
import { Season } from "@/apis/seasonApi";
|
||||
import { Show } from "@/apis/showApi";
|
||||
import styles from "@/app/tabStyles/indexStyles";
|
||||
@@ -10,6 +10,7 @@ import Feather from "@expo/vector-icons/Feather";
|
||||
import React from "react";
|
||||
import { Keyboard, ScrollView, Text, TextInput, TouchableOpacity, View } from "react-native";
|
||||
|
||||
import { useSearch } from "@/hooks/useSearch";
|
||||
import { getShowById } from "@/apis/showApi";
|
||||
import PersonRow from "@/components/discovery/PersonRow";
|
||||
import SeasonCarousel from "@/components/discovery/SeasonCarousel";
|
||||
@@ -20,25 +21,19 @@ export default function ExploreScreen() {
|
||||
const { query, setQuery, suggestions } = useDiscoveryContext();
|
||||
|
||||
const [tags, setTags] = React.useState<AutoCompleteItem[]>([]);
|
||||
const [results, setResults] = React.useState<SearchResultItem[]>([]);
|
||||
const tagStrings = React.useMemo(() => tags.map((t) => t.text), [tags]);
|
||||
const { data: results = [] } = useSearch(tagStrings);
|
||||
|
||||
// Show metadata cache by id (filled from SHOW results and lazy-loaded by id)
|
||||
const [showsById, setShowsById] = React.useState<Record<number, Show>>({});
|
||||
|
||||
// --- helpers ---
|
||||
const tagStrings = React.useMemo(() => tags.map((t) => t.text), [tags]);
|
||||
|
||||
|
||||
function tagAdded(tag: AutoCompleteItem) {
|
||||
const nextTags = tags.some((t) => t.text === tag.text) ? tags : [...tags, tag];
|
||||
setTags(nextTags);
|
||||
|
||||
const inputs = nextTags.map((t) => t.text);
|
||||
getSearchResults(inputs, 50)
|
||||
.then((items) => {
|
||||
setResults(items || []);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
setQuery("");
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
@@ -46,12 +41,6 @@ export default function ExploreScreen() {
|
||||
function tagRemoved(tag: AutoCompleteItem) {
|
||||
const nextTags = tags.filter((t) => t.text !== tag.text);
|
||||
setTags(nextTags);
|
||||
const inputs = nextTags.map((t) => t.text);
|
||||
getSearchResults(inputs, 50)
|
||||
.then((items) => {
|
||||
setResults(items || []);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
// Keep our local show cache in sync with SHOW items returned by search
|
||||
@@ -135,7 +124,7 @@ export default function ExploreScreen() {
|
||||
<Text style={[styles.title, { fontSize: 28 }]}>Durchsuchen</Text>
|
||||
</View>
|
||||
|
||||
<View style={{ paddingHorizontal: 10 }}>
|
||||
<View style={styles.sectionContainer}>
|
||||
{/* Search bar */}
|
||||
<View style={styles.searchContainer}>
|
||||
<TextInput
|
||||
@@ -143,13 +132,7 @@ export default function ExploreScreen() {
|
||||
onChangeText={setQuery}
|
||||
placeholder="Wonach suchst du?"
|
||||
placeholderTextColor=""
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: "500",
|
||||
color: "hsl(221, 39%, 80%)",
|
||||
width: "90%",
|
||||
height: "100%",
|
||||
}}
|
||||
style={styles.searchInput}
|
||||
returnKeyType="search"
|
||||
onSubmitEditing={() => {
|
||||
if (!query.trim()) return;
|
||||
@@ -205,8 +188,8 @@ export default function ExploreScreen() {
|
||||
<ScrollView keyboardShouldPersistTaps="handled">
|
||||
{/* Personen Section (top) */}
|
||||
{persons.length > 0 && (
|
||||
<View style={{ width: "100%", paddingHorizontal: 10, marginBottom: 12 }}>
|
||||
<Text style={{ color: "white", fontSize: 18, fontWeight: "600", marginBottom: 6 }}>Personen</Text>
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>Personen</Text>
|
||||
{persons.slice(0, 5).map((p) => (
|
||||
<PersonRow key={`p-${p.personId ?? p.id}`} person={p}/>
|
||||
))}
|
||||
@@ -214,8 +197,8 @@ export default function ExploreScreen() {
|
||||
)}
|
||||
|
||||
{/* Staffeln grouped by Show with page view */}
|
||||
<View style={{ width: "100%", paddingHorizontal: 10 }}>
|
||||
<Text style={{ color: "white", fontSize: 18, fontWeight: "600", marginBottom: 6 }}>Staffeln</Text>
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>Staffeln</Text>
|
||||
|
||||
{Array.from(seasonsByShowId.entries()).map(([showId, seasons]) => {
|
||||
const show = showsById[Number(showId)];
|
||||
@@ -242,7 +225,7 @@ export default function ExploreScreen() {
|
||||
})}
|
||||
|
||||
{seasonsByShowId.size === 0 && (
|
||||
<Text style={{ color: "white", fontSize: 16, textAlign: "center", marginTop: 14 }}>
|
||||
<Text style={styles.centerText}>
|
||||
Keine Staffeln gefunden. Passe deine Tags an.
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import styles from "@/app/tabStyles/indexStyles";
|
||||
import ShowCard from "@/components/ui/ShowCard";
|
||||
import { useShowContext } from "@/contexts/ShowContext";
|
||||
import { useStreamingServiceContext } from "@/contexts/StreamingServiceContext";
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { useShows } from "@/hooks/useShows";
|
||||
import { useStreamingServices } from "@/hooks/useStreamingServices";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import { router } from "expo-router";
|
||||
import React from "react";
|
||||
import {
|
||||
@@ -18,54 +18,43 @@ import {
|
||||
} from "react-native-gesture-handler";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { shows, error, loading } = useShowContext();
|
||||
const { streamingServices } = useStreamingServiceContext();
|
||||
const [filteredShows, setFilteredShows] = React.useState(shows);
|
||||
const { data: shows = [], error, isLoading: loading } = useShows();
|
||||
const { data: streamingServices = {} } = useStreamingServices();
|
||||
const [activeFilter, setActiveFilter] = React.useState<string>("all");
|
||||
|
||||
const haptikFeedback = () => {
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
setFilteredShows(shows);
|
||||
}, [shows]);
|
||||
};
|
||||
|
||||
const handleFilter = (type: string) => {
|
||||
haptikFeedback();
|
||||
setActiveFilter(type);
|
||||
|
||||
|
||||
if (type === "all") {
|
||||
setFilteredShows(shows);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "live") {
|
||||
const filtered = shows.filter((show) => show.running);
|
||||
setFilteredShows(filtered);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === activeFilter) {
|
||||
setFilteredShows(shows);
|
||||
setActiveFilter('all');
|
||||
return;
|
||||
setActiveFilter("all");
|
||||
} else {
|
||||
setActiveFilter(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const filtered = shows.filter((show) =>
|
||||
show.streamingService.split(',').map(s => s.trim()).includes(type)
|
||||
);
|
||||
setFilteredShows(filtered);
|
||||
};
|
||||
|
||||
const filteredShows = React.useMemo(() => {
|
||||
if (activeFilter === "all") {
|
||||
return shows;
|
||||
}
|
||||
if (activeFilter === "live") {
|
||||
return shows.filter((show) => show.running);
|
||||
}
|
||||
return shows.filter((show) =>
|
||||
show.streamingService
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.includes(activeFilter)
|
||||
);
|
||||
}, [shows, activeFilter]);
|
||||
|
||||
const uniqueStreamingServices = React.useMemo(() => {
|
||||
const uniqueServices = new Set<string>();
|
||||
shows.forEach((show) => {
|
||||
const services = show.streamingService.split(', ').map(s => s.trim());
|
||||
services.forEach(service => uniqueServices.add(service));
|
||||
const services = show.streamingService.split(", ").map((s) => s.trim());
|
||||
services.forEach((service) => uniqueServices.add(service));
|
||||
});
|
||||
return Array.from(uniqueServices);
|
||||
}, [shows]);
|
||||
@@ -91,7 +80,7 @@ export default function HomeScreen() {
|
||||
{ justifyContent: "center", alignItems: "center" },
|
||||
]}
|
||||
>
|
||||
<Text>Error: {error}</Text>
|
||||
<Text>Error: {error?.message || String(error)}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -102,7 +91,10 @@ export default function HomeScreen() {
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>FLTR</Text>
|
||||
</View>
|
||||
<ScrollView contentContainerStyle={{ paddingBottom: 30 }}>
|
||||
<ScrollView
|
||||
contentContainerStyle={{ paddingBottom: 30 }}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
>
|
||||
<View style={styles.filterSection}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
@@ -127,7 +119,9 @@ export default function HomeScreen() {
|
||||
}}
|
||||
onPress={() => handleFilter("all")}
|
||||
>
|
||||
<Text style={{fontWeight: 'bold', color: 'white'}}>ALLE</Text>
|
||||
<Text style={{ fontWeight: "bold", color: "white" }}>
|
||||
ALLE
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{activeFilter !== "live" && (
|
||||
@@ -143,25 +137,35 @@ export default function HomeScreen() {
|
||||
}}
|
||||
onPress={() => handleFilter("live")}
|
||||
>
|
||||
<View style={{backgroundColor: "red", paddingHorizontal: 5, paddingVertical: 2, borderRadius: 5}}>
|
||||
<Text style={{fontWeight: 'bold', color: 'white'}}>LIVE</Text>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "red",
|
||||
paddingHorizontal: 5,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 5,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontWeight: "bold", color: "white" }}>
|
||||
LIVE
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
<View style={{
|
||||
height: 60,
|
||||
width: 2,
|
||||
backgroundColor: "hsla(0, 0%, 37%, 1.00)",
|
||||
marginHorizontal: 5,
|
||||
borderRadius: 5,
|
||||
|
||||
}} />
|
||||
<View
|
||||
style={{
|
||||
height: 60,
|
||||
width: 2,
|
||||
backgroundColor: "hsla(0, 0%, 37%, 1.00)",
|
||||
marginHorizontal: 5,
|
||||
borderRadius: 5,
|
||||
}}
|
||||
/>
|
||||
|
||||
{uniqueStreamingServices.map((serviceName) => {
|
||||
const streamingService =
|
||||
streamingServices[
|
||||
`assets.images.streamingServices.${serviceName.toLowerCase()}`
|
||||
`assets.images.streamingServices.${serviceName.toLowerCase()}`
|
||||
];
|
||||
return (
|
||||
<TouchableOpacity
|
||||
@@ -214,13 +218,20 @@ export default function HomeScreen() {
|
||||
})
|
||||
}
|
||||
imageUri={show.bannerUri}
|
||||
streamingServicesUris={show.streamingService.split(', ').map(s => streamingServices[`assets.images.streamingServices.${s.toLowerCase()}`])}
|
||||
streamingServicesUris={show.streamingService
|
||||
.split(", ")
|
||||
.map(
|
||||
(s) =>
|
||||
streamingServices[
|
||||
`assets.images.streamingServices.${s.toLowerCase()}`
|
||||
]
|
||||
)}
|
||||
genres={show.genres}
|
||||
{...(showLiveBadge
|
||||
? {
|
||||
liveBadgeText: "LIVE",
|
||||
liveBadgeContainerStyle: styles.liveBadgeContainer,
|
||||
}
|
||||
liveBadgeText: "LIVE",
|
||||
liveBadgeContainerStyle: styles.liveBadgeContainer,
|
||||
}
|
||||
: {})}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,34 +1,30 @@
|
||||
import { DiscoveryProvider } from "@/contexts/DiscoveryContext";
|
||||
import { SeasonProvider } from "@/contexts/SeasonContext";
|
||||
import { ShowProvider } from "@/contexts/ShowContext";
|
||||
import { StreamingServiceProvider } from "@/contexts/StreamingServiceContext";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Stack } from "expo-router";
|
||||
import "react-native-reanimated";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export default function RootLayout() {
|
||||
return (
|
||||
<ShowProvider>
|
||||
<SeasonProvider>
|
||||
<StreamingServiceProvider>
|
||||
<DiscoveryProvider>
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="showDetails"
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="participant"
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</DiscoveryProvider>
|
||||
</StreamingServiceProvider>
|
||||
</SeasonProvider>
|
||||
</ShowProvider>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<DiscoveryProvider>
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="showDetails"
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="participant"
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</DiscoveryProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { getPersonHistory, type PersonMini } from "@/apis/personHistoryApi";
|
||||
import { getShowById } from "@/apis/showApi";
|
||||
import { PersonMini } from "@/apis/personHistoryApi";
|
||||
import styles from "@/app/stackStyles/participantStyles";
|
||||
import { useShowContext } from "@/contexts/ShowContext";
|
||||
import { usePersonHistory, AppearanceGroup } from "@/hooks/usePersonHistory";
|
||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
@@ -12,35 +11,14 @@ import {
|
||||
ScrollView,
|
||||
} from "react-native-gesture-handler";
|
||||
|
||||
type SeasonEntry = {
|
||||
seasonNumber: number;
|
||||
partner: PersonMini | null;
|
||||
participants: PersonMini[];
|
||||
startDate: string | null;
|
||||
};
|
||||
|
||||
type AppearanceGroup = {
|
||||
show: {
|
||||
id: number;
|
||||
title: string;
|
||||
bannerUri: string;
|
||||
thumbnailUri: string;
|
||||
};
|
||||
seasons: SeasonEntry[];
|
||||
};
|
||||
|
||||
export default function ParticipantScreen() {
|
||||
const { shows } = useShowContext();
|
||||
const { name, participantId } = useLocalSearchParams();
|
||||
|
||||
const pid = Array.isArray(participantId)
|
||||
? Number(participantId[0])
|
||||
: Number(participantId);
|
||||
|
||||
const [, setLoading] = React.useState(false);
|
||||
const [, setError] = React.useState<string | null>(null);
|
||||
|
||||
const [appearances, setAppearances] = React.useState<AppearanceGroup[]>([]);
|
||||
const { data: appearances = [], isLoading, isError } = usePersonHistory(pid);
|
||||
|
||||
const formatYear = (iso?: string | null) => {
|
||||
if (!iso) return null;
|
||||
@@ -48,104 +26,6 @@ export default function ParticipantScreen() {
|
||||
return y || null;
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!pid || Number.isNaN(pid)) return;
|
||||
const controller = new AbortController();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const hist = await getPersonHistory(pid, controller.signal);
|
||||
|
||||
const grouped = new Map<number, Map<number, SeasonEntry>>();
|
||||
for (const h of hist) {
|
||||
if (!Number.isFinite(h.showId) || h.showId <= 0) continue;
|
||||
const seasonsForShow =
|
||||
grouped.get(h.showId) ?? new Map<number, SeasonEntry>();
|
||||
|
||||
const existing = seasonsForShow.get(h.seasonNumber);
|
||||
if (existing) {
|
||||
seasonsForShow.set(h.seasonNumber, {
|
||||
seasonNumber: h.seasonNumber,
|
||||
partner: existing.partner ?? h.partner ?? null,
|
||||
participants: existing.participants.length
|
||||
? existing.participants
|
||||
: (h.seasonParticipants ?? []),
|
||||
startDate: existing.startDate ?? h.startDate ?? null,
|
||||
});
|
||||
} else {
|
||||
seasonsForShow.set(h.seasonNumber, {
|
||||
seasonNumber: h.seasonNumber,
|
||||
partner: h.partner ?? null,
|
||||
participants: h.seasonParticipants ?? [],
|
||||
startDate: h.startDate ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
grouped.set(h.showId, seasonsForShow);
|
||||
}
|
||||
|
||||
const showIds = Array.from(grouped.keys());
|
||||
|
||||
const fromContext = showIds
|
||||
.map((id) => shows.find((s) => s.id === id))
|
||||
.filter((s): s is (typeof shows)[number] => !!s);
|
||||
|
||||
const missingIds = showIds.filter(
|
||||
(id) => !fromContext.some((s) => s.id === id)
|
||||
);
|
||||
|
||||
const fetched = await Promise.all(
|
||||
missingIds.map(async (id) => {
|
||||
try {
|
||||
const s = await getShowById(id);
|
||||
return s;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const allShows = [
|
||||
...fromContext,
|
||||
...fetched.filter(Boolean),
|
||||
] as typeof shows;
|
||||
|
||||
const result: AppearanceGroup[] = allShows.map((s) => {
|
||||
const seasonsMap = grouped.get(s.id)!;
|
||||
const seasonsSorted = Array.from(seasonsMap.values()).sort(
|
||||
(a, b) => a.seasonNumber - b.seasonNumber
|
||||
);
|
||||
return {
|
||||
show: {
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
bannerUri: s.bannerUri,
|
||||
thumbnailUri: s.thumbnailUri,
|
||||
},
|
||||
seasons: seasonsSorted,
|
||||
};
|
||||
});
|
||||
|
||||
result.sort((a, b) =>
|
||||
a.show.title.localeCompare(b.show.title, "de", {
|
||||
sensitivity: "base",
|
||||
})
|
||||
);
|
||||
|
||||
setAppearances(result);
|
||||
} catch (e: any) {
|
||||
if (!controller.signal.aborted)
|
||||
setError(e?.message || "Fehler beim Laden");
|
||||
} finally {
|
||||
if (!controller.signal.aborted) setLoading(false);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => controller.abort();
|
||||
}, [pid, shows]);
|
||||
|
||||
const [expandedShows, setExpandedShows] = React.useState<Set<number>>(
|
||||
new Set()
|
||||
);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { getShowById, Show } from "@/apis/showApi";
|
||||
|
||||
import ParticipantDetails from "@/components/ui/ParticipantDeatails";
|
||||
|
||||
import ShowInfo from "@/components/ui/ShowInfo";
|
||||
import StackHeader from "@/components/ui/StackHeader";
|
||||
import { useSeasonContext } from "@/contexts/SeasonContext";
|
||||
import {
|
||||
useSeasonCount,
|
||||
useSeasonDates,
|
||||
useSeasonParticipants,
|
||||
} from "@/hooks/useSeason";
|
||||
import { useShow } from "@/hooks/useShow";
|
||||
import * as Haptics from "expo-haptics";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import {
|
||||
Dimensions,
|
||||
Image,
|
||||
@@ -19,93 +21,34 @@ import {
|
||||
import styles from "./stackStyles/showDetailStyles";
|
||||
|
||||
export default function ShowDetails() {
|
||||
const {
|
||||
// bannerUri,
|
||||
// description,
|
||||
// concept,
|
||||
// genres,
|
||||
// streamingService,
|
||||
id,
|
||||
// endDate,
|
||||
} = useLocalSearchParams();
|
||||
|
||||
const [show, setShow] = useState<Show | null>(null);
|
||||
const [, setLoading] = useState(true);
|
||||
const { id } = useLocalSearchParams();
|
||||
const showId = Number(id);
|
||||
|
||||
const [selectedParticipants, setSelectedParticipants] =
|
||||
React.useState<boolean>(true);
|
||||
const [selectedSeason, setSelectedSeason] = React.useState<number>(1);
|
||||
const showId = Number(id);
|
||||
const { fetchSeasonParticipants, fetchSeasonCount, fetchSeasonDates } =
|
||||
useSeasonContext();
|
||||
const [seasonCount, setSeasonCount] = React.useState<number>(0);
|
||||
const [participants, setParticipants] = React.useState<
|
||||
{ id: number; name: string; imageUri: string }[]
|
||||
>([]);
|
||||
const [startDate, setStartDate] = React.useState<string | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [pLoading, setPLoading] = React.useState(false);
|
||||
const [pError, setPError] = React.useState<string | null>(null);
|
||||
|
||||
const { data: show } = useShow(showId);
|
||||
const { data: seasonCount = 0 } = useSeasonCount(showId);
|
||||
const {
|
||||
data: participants,
|
||||
isLoading: pLoading,
|
||||
isError: pError,
|
||||
} = useSeasonParticipants(showId, selectedSeason);
|
||||
const { data: dates } = useSeasonDates(showId, selectedSeason);
|
||||
const startDate = dates?.startDate;
|
||||
|
||||
const sortedParticipants = React.useMemo(() => {
|
||||
return participants.sort((a, b) =>
|
||||
return [...participants].sort((a, b) =>
|
||||
a.name.localeCompare(b.name, "de", { sensitivity: "base" })
|
||||
);
|
||||
}, [participants]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!showId) return;
|
||||
|
||||
const fetchShow = async () => {
|
||||
try {
|
||||
const data = await getShowById(showId);
|
||||
setShow(data);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchShow();
|
||||
|
||||
let active = true;
|
||||
(async () => {
|
||||
const count = await fetchSeasonCount(showId);
|
||||
if (active) {
|
||||
setSeasonCount(count);
|
||||
if (count > 0 && selectedSeason > count) setSelectedSeason(1);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [showId, fetchSeasonCount, selectedSeason]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!showId || !selectedSeason) return;
|
||||
let active = true;
|
||||
(async () => {
|
||||
setPError(null);
|
||||
setPLoading(true);
|
||||
try {
|
||||
const [data, dates] = await Promise.all([
|
||||
fetchSeasonParticipants(showId, selectedSeason),
|
||||
fetchSeasonDates(showId, selectedSeason),
|
||||
]);
|
||||
if (active) {
|
||||
setParticipants(data);
|
||||
setStartDate(dates?.startDate);
|
||||
}
|
||||
} catch {
|
||||
if (active) setPError("Fehler beim Laden");
|
||||
} finally {
|
||||
if (active) setPLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [showId, selectedSeason, fetchSeasonParticipants, fetchSeasonDates]);
|
||||
if (seasonCount > 0 && selectedSeason > seasonCount) {
|
||||
setSelectedSeason(1);
|
||||
}
|
||||
}, [seasonCount, selectedSeason]);
|
||||
|
||||
const formattedStartDate = React.useMemo(() => {
|
||||
if (!startDate) return "";
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Dimensions, StyleSheet } from "react-native";
|
||||
import { Colors } from "@/constants/colors";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
mainContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
backgroundColor: Colors.header,
|
||||
},
|
||||
closeIcon: {
|
||||
position: "absolute",
|
||||
@@ -11,7 +12,7 @@ const styles = StyleSheet.create({
|
||||
right: 15,
|
||||
},
|
||||
participantName: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 20,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
@@ -27,7 +28,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
participantInfoSection: {
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
minHeight: "auto",
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
@@ -35,7 +36,7 @@ const styles = StyleSheet.create({
|
||||
marginTop: 5,
|
||||
},
|
||||
participantInfo: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
},
|
||||
@@ -43,20 +44,20 @@ const styles = StyleSheet.create({
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: 3,
|
||||
backgroundColor: "hsl(0, 0%, 80%)",
|
||||
backgroundColor: Colors.textSecondary,
|
||||
marginHorizontal: 7,
|
||||
marginTop: 2,
|
||||
},
|
||||
performedShowsSection: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: 'hsl(221, 39%, 16%)',
|
||||
backgroundColor: Colors.background,
|
||||
marginTop: 20,
|
||||
},
|
||||
performedShowsTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
marginTop: 15,
|
||||
marginLeft: 15,
|
||||
},
|
||||
@@ -67,7 +68,7 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 10,
|
||||
},
|
||||
showLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
@@ -83,14 +84,14 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: "#eee",
|
||||
},
|
||||
showTitle: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
marginTop: 15,
|
||||
},
|
||||
showSeason: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 12,
|
||||
fontWeight: "400",
|
||||
textAlign: "center",
|
||||
@@ -102,7 +103,7 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 15,
|
||||
marginTop: 20,
|
||||
alignItems: "center",
|
||||
backgroundColor: "hsl(336, 79%, 63%)",
|
||||
backgroundColor: Colors.primary,
|
||||
},
|
||||
|
||||
card: {
|
||||
@@ -113,12 +114,12 @@ const styles = StyleSheet.create({
|
||||
horizontalLine: {
|
||||
height: 50,
|
||||
width: 2,
|
||||
backgroundColor: "hsl(0, 0%, 70%)",
|
||||
backgroundColor: Colors.textSecondary,
|
||||
marginTop: 10,
|
||||
alignSelf: "center",
|
||||
},
|
||||
partnerLabel: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 12,
|
||||
fontWeight: "400",
|
||||
textAlign: "center",
|
||||
@@ -126,17 +127,17 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
participantContainer: {
|
||||
width: "auto",
|
||||
height: "auto",
|
||||
minHeight: "auto",
|
||||
borderRadius: 15,
|
||||
marginTop: 15,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
backgroundColor: Colors.header,
|
||||
padding: 10,
|
||||
},
|
||||
|
||||
participantLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
},
|
||||
participantRow: {
|
||||
@@ -167,7 +168,7 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: "hsl(221, 39%, 28%)",
|
||||
},
|
||||
moreChipText: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 11,
|
||||
fontWeight: "600",
|
||||
},
|
||||
@@ -175,7 +176,7 @@ const styles = StyleSheet.create({
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
backgroundColor: Colors.header,
|
||||
marginLeft: 15,
|
||||
marginTop: 15,
|
||||
marginBottom: 5,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
import { Colors } from "@/constants/colors";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
mainContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
backgroundColor: Colors.header,
|
||||
},
|
||||
showImage: {
|
||||
width: 200,
|
||||
@@ -22,14 +23,14 @@ const styles = StyleSheet.create({
|
||||
bottom: 25,
|
||||
},
|
||||
showInfoText: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 14,
|
||||
},
|
||||
dot: {
|
||||
width: 4,
|
||||
height: 4,
|
||||
borderRadius: 3,
|
||||
backgroundColor: "hsl(0, 0%, 80%)",
|
||||
backgroundColor: Colors.textSecondary,
|
||||
marginHorizontal: 7,
|
||||
marginTop: 2,
|
||||
},
|
||||
@@ -49,27 +50,27 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
infoContainner: {
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
minHeight: "auto",
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 15,
|
||||
backgroundColor: "hsl(221, 39%, 0%)",
|
||||
backgroundColor: Colors.background,
|
||||
flexDirection: "row",
|
||||
gap: 20,
|
||||
},
|
||||
infoLabel: {
|
||||
fontWeight: "300",
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 16,
|
||||
},
|
||||
participantsDetailsContainer: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "hsl(221, 39%, 2%)",
|
||||
backgroundColor: Colors.card,
|
||||
},
|
||||
participantContainer: {
|
||||
height: 160,
|
||||
width: 110,
|
||||
backgroundColor: "hsl(336, 79%, 63%)",
|
||||
backgroundColor: Colors.primary,
|
||||
borderRadius: 10,
|
||||
marginBottom: 30,
|
||||
},
|
||||
@@ -82,8 +83,8 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
seasonsSection: {
|
||||
width: "100%",
|
||||
height: 40,
|
||||
backgroundColor: "hsl(221, 39%, 2%)",
|
||||
minHeight: 40,
|
||||
backgroundColor: Colors.card,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
@@ -105,23 +106,23 @@ const styles = StyleSheet.create({
|
||||
alignItems: "center",
|
||||
},
|
||||
seasonLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
participantLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
fontSize: 11,
|
||||
marginTop: 10,
|
||||
},
|
||||
seasonsLabel: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontWeight: "500",
|
||||
fontSize: 16,
|
||||
},
|
||||
detailTitle: {
|
||||
color: "hsl(0, 0%, 100%)",
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
@@ -129,7 +130,7 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 5,
|
||||
},
|
||||
detailLabel: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
width: "90%",
|
||||
@@ -138,7 +139,7 @@ const styles = StyleSheet.create({
|
||||
marginTop: 5,
|
||||
},
|
||||
startDate: {
|
||||
color: "hsl(0, 0%, 80%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
marginTop: 15,
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
import { Colors } from "@/constants/colors";
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
const shadow = {
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
};
|
||||
|
||||
export default StyleSheet.create({
|
||||
mainContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "hsl(221, 39%, 11%)",
|
||||
// paddingHorizontal: 10,
|
||||
backgroundColor: Colors.background,
|
||||
paddingHorizontal: 15,
|
||||
},
|
||||
header: {
|
||||
height: 125,
|
||||
backgroundColor: "hsl(221, 39%, 12%)",
|
||||
minHeight: 125,
|
||||
backgroundColor: Colors.header,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "hsl(221, 39%, 15%)",
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 3,
|
||||
},
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
borderRadius: 25,
|
||||
marginBottom: 15,
|
||||
borderBottomColor: Colors.border,
|
||||
...shadow,
|
||||
},
|
||||
title: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 38,
|
||||
fontWeight: "bold",
|
||||
marginTop: "auto",
|
||||
@@ -33,38 +40,37 @@ export default StyleSheet.create({
|
||||
position: "absolute",
|
||||
top: 15,
|
||||
left: 20,
|
||||
backgroundColor: "red",
|
||||
backgroundColor: Colors.red,
|
||||
borderRadius: 10,
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
filterSection: {
|
||||
width: "100%",
|
||||
height: 70,
|
||||
minHeight: 70,
|
||||
marginTop: 20,
|
||||
},
|
||||
searchContainer: {
|
||||
width: "100%",
|
||||
height: 60,
|
||||
marginHorizontal: "auto",
|
||||
backgroundColor: "hsl(221, 39%, 8%)",
|
||||
backgroundColor: Colors.card,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
borderRadius: 20,
|
||||
paddingHorizontal: 20,
|
||||
|
||||
marginTop: 15,
|
||||
borderWidth: 1.5,
|
||||
borderColor: "hsl(221, 39%, 15%)",
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
borderColor: Colors.border,
|
||||
...shadow,
|
||||
},
|
||||
searchInput: {
|
||||
fontSize: 18,
|
||||
fontWeight: "500",
|
||||
color: "hsl(221, 39%, 80%)",
|
||||
width: "90%",
|
||||
height: "100%",
|
||||
},
|
||||
searchLabel: {
|
||||
color: "hsl(221, 39%, 80%)",
|
||||
@@ -79,24 +85,16 @@ export default StyleSheet.create({
|
||||
height: "auto",
|
||||
paddingBottom: 15,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "hsl(221, 39%, 8%)",
|
||||
backgroundColor: Colors.card,
|
||||
borderWidth: 1.5,
|
||||
borderColor: "hsl(221, 39%, 15%)",
|
||||
borderColor: Colors.border,
|
||||
marginHorizontal: "auto",
|
||||
alignSelf: "center",
|
||||
marginTop: 15,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
// opacity: 0.9,
|
||||
...shadow,
|
||||
},
|
||||
suggestionTitle: {
|
||||
color: "hsl(0, 0%, 60%)",
|
||||
color: Colors.textSecondary,
|
||||
fontSize: 14,
|
||||
marginLeft: 15,
|
||||
marginTop: 15,
|
||||
@@ -116,10 +114,10 @@ export default StyleSheet.create({
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1.5,
|
||||
borderColor: "hsl(0, 0%, 90%)",
|
||||
borderColor: Colors.text,
|
||||
},
|
||||
suggestionLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
fontWeight: "500",
|
||||
marginLeft: 10,
|
||||
@@ -136,7 +134,7 @@ export default StyleSheet.create({
|
||||
marginTop: 5,
|
||||
},
|
||||
tagLabel: {
|
||||
color: "white",
|
||||
color: Colors.text,
|
||||
marginRight: 5,
|
||||
},
|
||||
tagContainer: {
|
||||
@@ -164,6 +162,23 @@ export default StyleSheet.create({
|
||||
justifyContent: "center",
|
||||
marginRight: 10,
|
||||
},
|
||||
personName: { color: "white", fontSize: 16, fontWeight: "600" },
|
||||
personName: { color: Colors.text, fontSize: 16, fontWeight: "600" },
|
||||
personMeta: { color: "#bbb", fontSize: 12, marginTop: 2 },
|
||||
sectionContainer: {
|
||||
width: "100%",
|
||||
paddingHorizontal: 10,
|
||||
marginBottom: 12,
|
||||
},
|
||||
sectionTitle: {
|
||||
color: Colors.text,
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
marginBottom: 6,
|
||||
},
|
||||
centerText: {
|
||||
color: Colors.text,
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
marginTop: 14,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user