161 lines
4.2 KiB
TypeScript
161 lines
4.2 KiB
TypeScript
import { LeagueInfo } from "@/components/match-detail/league-info";
|
|
import { MatchInfoCard } from "@/components/match-detail/match-info-card";
|
|
import { MatchTabs } from "@/components/match-detail/match-tabs";
|
|
import { ScoreHeader } from "@/components/match-detail/score-header";
|
|
import { ScoreTable } from "@/components/match-detail/score-table";
|
|
import { ThemedText } from "@/components/themed-text";
|
|
import { ThemedView } from "@/components/themed-view";
|
|
import { Colors } from "@/constants/theme";
|
|
import { useTheme } from "@/context/ThemeContext";
|
|
import { fetchMatchDetail } from "@/lib/api";
|
|
import { MatchDetailData } from "@/types/api";
|
|
import { Stack, useLocalSearchParams, useRouter } from "expo-router";
|
|
import React, { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import {
|
|
ActivityIndicator,
|
|
ScrollView,
|
|
StyleSheet,
|
|
TouchableOpacity,
|
|
View,
|
|
} from "react-native";
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
|
|
export default function MatchDetailScreen() {
|
|
const { id } = useLocalSearchParams<{ id: string }>();
|
|
const router = useRouter();
|
|
const { theme } = useTheme();
|
|
const { t } = useTranslation();
|
|
const insets = useSafeAreaInsets();
|
|
const isDark = theme === "dark";
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [data, setData] = useState<MatchDetailData | null>(null);
|
|
const [activeTab, setActiveTab] = useState("info");
|
|
|
|
useEffect(() => {
|
|
if (id) {
|
|
loadMatchDetail();
|
|
}
|
|
}, [id]);
|
|
|
|
const loadMatchDetail = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
const result = await fetchMatchDetail(id as string);
|
|
setData(result);
|
|
} catch (err: any) {
|
|
setError(err.message || t("detail.fetch_failed"));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<ThemedView style={styles.center}>
|
|
<ActivityIndicator size="large" color={Colors[theme].tint} />
|
|
</ThemedView>
|
|
);
|
|
}
|
|
|
|
if (error || !data) {
|
|
return (
|
|
<ThemedView style={styles.center}>
|
|
<ThemedText>{error || t("detail.not_found")}</ThemedText>
|
|
<TouchableOpacity style={styles.retryButton} onPress={loadMatchDetail}>
|
|
<ThemedText style={styles.retryText}>{t("detail.retry")}</ThemedText>
|
|
</TouchableOpacity>
|
|
</ThemedView>
|
|
);
|
|
}
|
|
|
|
const renderTabContent = () => {
|
|
switch (activeTab) {
|
|
case "info":
|
|
return (
|
|
<>
|
|
<ScoreTable data={data} isDark={isDark} />
|
|
<MatchInfoCard data={data} isDark={isDark} />
|
|
</>
|
|
);
|
|
case "h2h":
|
|
return (
|
|
<View style={styles.emptyContent}>
|
|
<ThemedText style={styles.emptyText}>
|
|
{t("detail.empty_h2h")}
|
|
</ThemedText>
|
|
</View>
|
|
);
|
|
case "chat":
|
|
return (
|
|
<View style={styles.emptyContent}>
|
|
<ThemedText style={styles.emptyText}>
|
|
{t("detail.empty_chat")}
|
|
</ThemedText>
|
|
</View>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<ThemedView style={styles.container}>
|
|
<Stack.Screen options={{ headerShown: false }} />
|
|
|
|
<ScrollView
|
|
bounces={false}
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={{ paddingBottom: insets.bottom + 20 }}
|
|
>
|
|
<ScoreHeader data={data} isDark={isDark} topInset={insets.top} />
|
|
<LeagueInfo data={data} isDark={isDark} />
|
|
<MatchTabs
|
|
activeTab={activeTab}
|
|
onTabChange={setActiveTab}
|
|
isDark={isDark}
|
|
/>
|
|
|
|
{renderTabContent()}
|
|
</ScrollView>
|
|
</ThemedView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
center: {
|
|
flex: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
padding: 20,
|
|
},
|
|
errorText: {
|
|
fontSize: 16,
|
|
marginBottom: 20,
|
|
textAlign: "center",
|
|
},
|
|
retryButton: {
|
|
paddingHorizontal: 20,
|
|
paddingVertical: 10,
|
|
backgroundColor: "#007AFF",
|
|
borderRadius: 8,
|
|
},
|
|
retryText: {
|
|
color: "#FFF",
|
|
fontWeight: "600",
|
|
},
|
|
emptyContent: {
|
|
padding: 50,
|
|
alignItems: "center",
|
|
},
|
|
emptyText: {
|
|
opacity: 0.5,
|
|
},
|
|
});
|