218 lines
6.9 KiB
TypeScript
218 lines
6.9 KiB
TypeScript
import ParticipantDetails from "@/components/ui/ParticipantDeatails";
|
|
import ShowInfo from "@/components/ui/ShowInfo";
|
|
import StackHeader from "@/components/ui/StackHeader";
|
|
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 from "react";
|
|
import {
|
|
Dimensions,
|
|
Image,
|
|
ScrollView,
|
|
Text,
|
|
TouchableOpacity,
|
|
View,
|
|
} from "react-native";
|
|
import styles from "./stackStyles/showDetailStyles";
|
|
|
|
export default function ShowDetails() {
|
|
const { id } = useLocalSearchParams();
|
|
const showId = Number(id);
|
|
|
|
const [selectedParticipants, setSelectedParticipants] =
|
|
React.useState<boolean>(true);
|
|
const [selectedSeason, setSelectedSeason] = React.useState<number>(1);
|
|
|
|
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) =>
|
|
a.name.localeCompare(b.name, "de", { sensitivity: "base" })
|
|
);
|
|
}, [participants]);
|
|
|
|
React.useEffect(() => {
|
|
if (seasonCount > 0 && selectedSeason > seasonCount) {
|
|
setSelectedSeason(1);
|
|
}
|
|
}, [seasonCount, selectedSeason]);
|
|
|
|
const formattedStartDate = React.useMemo(() => {
|
|
if (!startDate) return "";
|
|
const d = new Date(startDate);
|
|
if (isNaN(d.getTime())) return "";
|
|
return d.toLocaleDateString("de-DE", {
|
|
day: "2-digit",
|
|
month: "long",
|
|
year: "numeric",
|
|
});
|
|
}, [startDate]);
|
|
|
|
const handleOpenParticipant = React.useCallback(
|
|
(p: { id: number; name: string }) => {
|
|
router.push({
|
|
pathname: "/participant",
|
|
params: {
|
|
participantId: p.id,
|
|
name: p.name,
|
|
originShowId: String(showId),
|
|
originSeason: String(selectedSeason),
|
|
},
|
|
});
|
|
},
|
|
[showId, selectedSeason]
|
|
);
|
|
|
|
return (
|
|
<View style={styles.mainContainer}>
|
|
<StackHeader />
|
|
<ScrollView
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={{
|
|
paddingBottom: Dimensions.get("window").height * 0.1,
|
|
}}
|
|
>
|
|
{formattedStartDate ? (
|
|
<Text style={styles.startDate}>{formattedStartDate}</Text>
|
|
) : null}
|
|
<ShowInfo
|
|
seasons={seasonCount}
|
|
participants={participants.length}
|
|
streamingService={show?.streamingService as string}
|
|
startDate={startDate as string}
|
|
endDate={show?.endDate as string | null}
|
|
/>
|
|
|
|
<View style={styles.showBannerLogoContainer}>
|
|
<Image
|
|
source={{
|
|
uri: show?.bannerUri as string,
|
|
}}
|
|
style={styles.showBannerLogo}
|
|
resizeMode="cover"
|
|
/>
|
|
</View>
|
|
<View style={styles.infoContainner}>
|
|
<TouchableOpacity onPress={() => setSelectedParticipants(true)}>
|
|
<Text
|
|
style={[
|
|
styles.infoLabel,
|
|
{
|
|
fontWeight: selectedParticipants ? "bold" : "normal",
|
|
color: selectedParticipants ? "#199edb" : "hsl(0, 0%, 65%)",
|
|
},
|
|
]}
|
|
>
|
|
Teilnehmer
|
|
</Text>
|
|
</TouchableOpacity>
|
|
<TouchableOpacity onPress={() => setSelectedParticipants(false)}>
|
|
<Text
|
|
style={[
|
|
styles.infoLabel,
|
|
{
|
|
fontWeight: !selectedParticipants ? "bold" : "normal",
|
|
color: !selectedParticipants ? "#199edb" : "hsl(0, 0%, 65%)",
|
|
},
|
|
]}
|
|
>
|
|
Details
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
{selectedParticipants ? (
|
|
<>
|
|
<View style={styles.seasonsSection}>
|
|
<Text style={styles.seasonsLabel}>Staffeln</Text>
|
|
<ScrollView
|
|
horizontal
|
|
showsHorizontalScrollIndicator={false}
|
|
contentContainerStyle={styles.seasonList}
|
|
>
|
|
{Array.from({ length: seasonCount }, (_, idx) => idx + 1).map(
|
|
(season) => (
|
|
<TouchableOpacity
|
|
key={season}
|
|
style={[
|
|
styles.seasonContainer,
|
|
{
|
|
backgroundColor:
|
|
selectedSeason === season
|
|
? "#199edb"
|
|
: "hsl(0, 0%, 20%)",
|
|
},
|
|
]}
|
|
onPress={() => {
|
|
setSelectedSeason(season);
|
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
|
}}
|
|
>
|
|
<Text style={styles.seasonLabel}>{season}</Text>
|
|
</TouchableOpacity>
|
|
)
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
|
|
<View
|
|
style={[
|
|
styles.participantsDetailsContainer,
|
|
styles.participantSection,
|
|
]}
|
|
>
|
|
{pError && (
|
|
<Text style={{ color: "tomato", marginBottom: 8 }}>
|
|
{pError}
|
|
</Text>
|
|
)}
|
|
{!pLoading && !pError && participants.length === 0 && (
|
|
<Text style={{ color: "gray" }}>Keine Teilnehmer.</Text>
|
|
)}
|
|
{sortedParticipants.map((p) => (
|
|
<TouchableOpacity
|
|
key={p.id}
|
|
style={[
|
|
styles.participantContainer,
|
|
{ backgroundColor: "hsl(336, 79%, 63%)" },
|
|
]}
|
|
onPress={() => handleOpenParticipant(p)}
|
|
>
|
|
<Image
|
|
source={{ uri: p.imageUri }}
|
|
style={{ width: "100%", height: "100%", borderRadius: 10 }}
|
|
resizeMode="cover"
|
|
blurRadius={p.imageUri.includes("pravatar") ? 16 : 0}
|
|
/>
|
|
<Text style={styles.participantLabel} numberOfLines={2}>
|
|
{p.name}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
</>
|
|
) : (
|
|
<ParticipantDetails
|
|
description={show?.description as string}
|
|
concept={show?.concept as string}
|
|
genres={show?.genres as string[]}
|
|
streamingService={show?.streamingService as string}
|
|
/>
|
|
)}
|
|
</ScrollView>
|
|
</View>
|
|
);
|
|
}
|