Files
physical-expo/components/live-detail/tennis-scoreboard.tsx
2026-01-22 18:48:39 +08:00

245 lines
6.5 KiB
TypeScript

import { ThemedText } from "@/components/themed-text";
import { LiveScoreMatch } from "@/types/api";
import { Image } from "expo-image";
import React from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet, View } from "react-native";
interface TennisScoreboardProps {
match: LiveScoreMatch;
isDark: boolean;
}
export function TennisScoreboard({ match, isDark }: TennisScoreboardProps) {
const { t } = useTranslation();
// Tennis Logic
const isTennis =
!!match.event_first_player ||
(match.league_name &&
/ATP|WTA|ITF|Challenger/i.test(match.league_name || ""));
if (!isTennis) return null;
const homeName = isTennis ? match.event_first_player : match.event_home_team;
const awayName = isTennis ? match.event_second_player : match.event_away_team;
const homeLogo = isTennis
? match.event_first_player_logo
: match.home_team_logo;
const awayLogo = isTennis
? match.event_second_player_logo
: match.away_team_logo;
const tennisScores = React.useMemo(() => {
if (!match.scores) return [];
try {
const s = match.scores;
return Array.isArray(s) ? s : [];
} catch {
return [];
}
}, [match.scores]);
const gamePoints = React.useMemo(() => {
if (!match.event_game_result) return { p1: "0", p2: "0" };
const parts = match.event_game_result.split("-");
if (parts.length === 2) {
return { p1: parts[0].trim(), p2: parts[1].trim() };
}
return { p1: "0", p2: "0" };
}, [match.event_game_result]);
const totalSets = React.useMemo(() => {
if (!match.event_final_result) return { p1: 0, p2: 0 };
const parts = match.event_final_result.split("-");
if (parts.length === 2) {
return {
p1: parseInt(parts[0].trim()) || 0,
p2: parseInt(parts[1].trim()) || 0,
};
}
return { p1: 0, p2: 0 };
}, [match.event_final_result]);
const bgColor = isDark ? "#1E1E20" : "#FFF";
const textColor = isDark ? "#FFF" : "#000";
const headerColor = isDark ? "#888" : "#666";
const borderColor = isDark ? "#333" : "#F0F0F0";
return (
<View style={[styles.tennisBoardContainer, { backgroundColor: bgColor }]}>
<View style={styles.header}>
<ThemedText
style={{ fontSize: 16, fontWeight: "700", marginBottom: 12 }}
>
{t("detail.scoreboard", "Scoreboard")}
</ThemedText>
</View>
<View
style={[styles.tennisBoardHeader, { borderBottomColor: borderColor }]}
>
<ThemedText style={[styles.boardHeaderLabel, { color: headerColor }]}>
Player
</ThemedText>
<ThemedText
style={[
styles.boardHeaderLabel,
styles.boardColCenter,
{ color: "#4CAF50" },
]}
>
Game
</ThemedText>
{[1, 2, 3, 4, 5].map((i) => (
<ThemedText
key={i}
style={[
styles.boardHeaderLabel,
styles.boardColCenter,
{
color:
i.toString() === match.event_status?.replace("Set ", "")
? "#4CAF50"
: headerColor,
},
]}
>
S{i}
</ThemedText>
))}
<ThemedText
style={[
styles.boardHeaderLabel,
styles.boardColCenter,
{ color: headerColor },
]}
>
Sets
</ThemedText>
</View>
<View style={styles.tennisRow}>
<View style={styles.boardPlayerCol}>
<Image source={{ uri: homeLogo }} style={styles.miniAvatar} />
</View>
<ThemedText
style={[styles.boardVal, styles.boardColCenter, { color: "#4CAF50" }]}
>
{gamePoints.p1}
</ThemedText>
{[1, 2, 3, 4, 5].map((i) => {
const setScore = tennisScores.find((s: any) => s.score_set == i);
return (
<ThemedText
key={i}
style={[
styles.boardVal,
styles.boardColCenter,
{
color:
i.toString() === match.event_status?.replace("Set ", "")
? "#4CAF50"
: textColor,
},
]}
>
{setScore ? setScore.score_first : "-"}
</ThemedText>
);
})}
<ThemedText
style={[styles.boardVal, styles.boardColCenter, { color: textColor }]}
>
{totalSets.p1}
</ThemedText>
</View>
<View style={styles.tennisRow}>
<View style={styles.boardPlayerCol}>
<Image source={{ uri: awayLogo }} style={styles.miniAvatar} />
</View>
<ThemedText
style={[styles.boardVal, styles.boardColCenter, { color: "#4CAF50" }]}
>
{gamePoints.p2}
</ThemedText>
{[1, 2, 3, 4, 5].map((i) => {
const setScore = tennisScores.find((s: any) => s.score_set == i);
return (
<ThemedText
key={i}
style={[
styles.boardVal,
styles.boardColCenter,
{
color:
i.toString() === match.event_status?.replace("Set ", "")
? "#4CAF50"
: textColor,
},
]}
>
{setScore ? setScore.score_second : "-"}
</ThemedText>
);
})}
<ThemedText
style={[styles.boardVal, styles.boardColCenter, { color: textColor }]}
>
{totalSets.p2}
</ThemedText>
</View>
</View>
);
}
const styles = StyleSheet.create({
tennisBoardContainer: {
marginHorizontal: 16,
borderRadius: 16,
padding: 16,
marginTop: 12,
marginBottom: 16,
shadowColor: "#000",
shadowOpacity: 0.05,
shadowRadius: 10,
elevation: 2,
},
header: {
flexDirection: "row",
justifyContent: "space-between",
},
tennisBoardHeader: {
flexDirection: "row",
alignItems: "center",
borderBottomWidth: 1,
paddingBottom: 8,
marginBottom: 8,
},
boardHeaderLabel: {
fontSize: 12,
fontWeight: "500",
},
boardPlayerCol: {
width: 40,
alignItems: "center",
},
boardColCenter: {
flex: 1,
textAlign: "center",
},
tennisRow: {
flexDirection: "row",
alignItems: "center",
height: 36,
},
miniAvatar: {
width: 28,
height: 28,
borderRadius: 14,
},
boardVal: {
fontSize: 14,
fontWeight: "600",
},
});