为比赛和球队添加收藏功能,更新状态检查和切换逻辑
This commit is contained in:
@@ -38,6 +38,11 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
|
|||||||
const [isFav, setIsFav] = useState(false);
|
const [isFav, setIsFav] = useState(false);
|
||||||
const [favLoading, setFavLoading] = useState(false);
|
const [favLoading, setFavLoading] = useState(false);
|
||||||
|
|
||||||
|
const [isHomeFav, setIsHomeFav] = useState(false);
|
||||||
|
const [isAwayFav, setIsAwayFav] = useState(false);
|
||||||
|
const [homeFavLoading, setHomeFavLoading] = useState(false);
|
||||||
|
const [awayFavLoading, setAwayFavLoading] = useState(false);
|
||||||
|
|
||||||
// 检查收藏状态
|
// 检查收藏状态
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const loadFavStatus = async () => {
|
const loadFavStatus = async () => {
|
||||||
@@ -51,6 +56,36 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
|
|||||||
loadFavStatus();
|
loadFavStatus();
|
||||||
}, [match.event_key]);
|
}, [match.event_key]);
|
||||||
|
|
||||||
|
// 检查主队收藏状态
|
||||||
|
React.useEffect(() => {
|
||||||
|
const loadHomeFav = async () => {
|
||||||
|
try {
|
||||||
|
const res = await checkFavorite("team", match.home_team_key.toString());
|
||||||
|
setIsHomeFav(res.isFavorite);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Check home team favorite status error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (match.home_team_key) {
|
||||||
|
loadHomeFav();
|
||||||
|
}
|
||||||
|
}, [match.home_team_key]);
|
||||||
|
|
||||||
|
// 检查客队收藏状态
|
||||||
|
React.useEffect(() => {
|
||||||
|
const loadAwayFav = async () => {
|
||||||
|
try {
|
||||||
|
const res = await checkFavorite("team", match.away_team_key.toString());
|
||||||
|
setIsAwayFav(res.isFavorite);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Check away team favorite status error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (match.away_team_key) {
|
||||||
|
loadAwayFav();
|
||||||
|
}
|
||||||
|
}, [match.away_team_key]);
|
||||||
|
|
||||||
const toggleFavorite = async () => {
|
const toggleFavorite = async () => {
|
||||||
if (favLoading) return;
|
if (favLoading) return;
|
||||||
setFavLoading(true);
|
setFavLoading(true);
|
||||||
@@ -76,6 +111,38 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
|
|||||||
setFavLoading(false);
|
setFavLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const toggleTeamFavorite = async (teamKey: number, isHome: boolean) => {
|
||||||
|
const isTeamFav = isHome ? isHomeFav : isAwayFav;
|
||||||
|
const setLoading = isHome ? setHomeFavLoading : setAwayFavLoading;
|
||||||
|
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
|
||||||
|
const loading = isHome ? homeFavLoading : awayFavLoading;
|
||||||
|
|
||||||
|
if (loading) return;
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const newFavState = !isTeamFav;
|
||||||
|
try {
|
||||||
|
if (newFavState) {
|
||||||
|
await addFavorite({
|
||||||
|
teamId: teamKey,
|
||||||
|
type: "team",
|
||||||
|
typeId: teamKey.toString(),
|
||||||
|
notify: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await removeFavorite({
|
||||||
|
type: "team",
|
||||||
|
typeId: teamKey.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setFav(newFavState);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Toggle team favorite error:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const lastServerMatchRef = React.useRef(
|
const lastServerMatchRef = React.useRef(
|
||||||
`${match.event_status}-${match.event_time}`
|
`${match.event_status}-${match.event_time}`
|
||||||
);
|
);
|
||||||
@@ -163,12 +230,25 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
|
|||||||
{/* Score Section */}
|
{/* Score Section */}
|
||||||
<View style={styles.scoreRow}>
|
<View style={styles.scoreRow}>
|
||||||
<View style={styles.teamInfo}>
|
<View style={styles.teamInfo}>
|
||||||
|
<View style={styles.teamLogoRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleTeamFavorite(match.home_team_key, true)}
|
||||||
|
disabled={homeFavLoading}
|
||||||
|
style={styles.starBtnLeft}
|
||||||
|
>
|
||||||
|
<IconSymbol
|
||||||
|
name={isHomeFav ? "star" : "star-outline"}
|
||||||
|
size={20}
|
||||||
|
color={isHomeFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
<View style={styles.logoContainer}>
|
<View style={styles.logoContainer}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: match.home_team_logo }}
|
source={{ uri: match.home_team_logo }}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
</View>
|
||||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||||
{match.event_home_team}
|
{match.event_home_team}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
@@ -202,12 +282,25 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.teamInfo}>
|
<View style={styles.teamInfo}>
|
||||||
|
<View style={styles.teamLogoRow}>
|
||||||
<View style={styles.logoContainer}>
|
<View style={styles.logoContainer}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: match.away_team_logo }}
|
source={{ uri: match.away_team_logo }}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleTeamFavorite(match.away_team_key, false)}
|
||||||
|
disabled={awayFavLoading}
|
||||||
|
style={styles.starBtnRight}
|
||||||
|
>
|
||||||
|
<IconSymbol
|
||||||
|
name={isAwayFav ? "star" : "star-outline"}
|
||||||
|
size={20}
|
||||||
|
color={isAwayFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||||
{match.event_away_team}
|
{match.event_away_team}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
@@ -261,13 +354,26 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: "30%",
|
width: "30%",
|
||||||
},
|
},
|
||||||
|
teamLogoRow: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
logoContainer: {
|
logoContainer: {
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 70,
|
height: 70,
|
||||||
marginBottom: 10,
|
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
starBtnLeft: {
|
||||||
|
padding: 8,
|
||||||
|
marginRight: -4,
|
||||||
|
},
|
||||||
|
starBtnRight: {
|
||||||
|
padding: 8,
|
||||||
|
marginLeft: -4,
|
||||||
|
},
|
||||||
teamLogo: {
|
teamLogo: {
|
||||||
width: 60,
|
width: 60,
|
||||||
height: 60,
|
height: 60,
|
||||||
|
|||||||
@@ -22,14 +22,19 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
|||||||
const [isFav, setIsFav] = useState(false);
|
const [isFav, setIsFav] = useState(false);
|
||||||
const [favLoading, setFavLoading] = useState(false);
|
const [favLoading, setFavLoading] = useState(false);
|
||||||
|
|
||||||
// 检查收藏状态
|
const [isHomeFav, setIsHomeFav] = useState(false);
|
||||||
|
const [isAwayFav, setIsAwayFav] = useState(false);
|
||||||
|
const [homeFavLoading, setHomeFavLoading] = useState(false);
|
||||||
|
const [awayFavLoading, setAwayFavLoading] = useState(false);
|
||||||
|
|
||||||
|
// 检查比赛收藏状态
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const loadFavStatus = async () => {
|
const loadFavStatus = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await checkFavorite("match", match.eventKey.toString());
|
const res = await checkFavorite("match", match.eventKey.toString());
|
||||||
setIsFav(res.isFavorite);
|
setIsFav(res.isFavorite);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Check favorite status error:", error);
|
console.error("Check match favorite status error:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (match.eventKey) {
|
if (match.eventKey) {
|
||||||
@@ -37,6 +42,36 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
|||||||
}
|
}
|
||||||
}, [match.eventKey]);
|
}, [match.eventKey]);
|
||||||
|
|
||||||
|
// 检查主队收藏状态
|
||||||
|
React.useEffect(() => {
|
||||||
|
const loadHomeFav = async () => {
|
||||||
|
try {
|
||||||
|
const res = await checkFavorite("team", match.homeTeamKey.toString());
|
||||||
|
setIsHomeFav(res.isFavorite);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Check home team favorite status error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (match.homeTeamKey) {
|
||||||
|
loadHomeFav();
|
||||||
|
}
|
||||||
|
}, [match.homeTeamKey]);
|
||||||
|
|
||||||
|
// 检查客队收藏状态
|
||||||
|
React.useEffect(() => {
|
||||||
|
const loadAwayFav = async () => {
|
||||||
|
try {
|
||||||
|
const res = await checkFavorite("team", match.awayTeamKey.toString());
|
||||||
|
setIsAwayFav(res.isFavorite);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Check away team favorite status error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (match.awayTeamKey) {
|
||||||
|
loadAwayFav();
|
||||||
|
}
|
||||||
|
}, [match.awayTeamKey]);
|
||||||
|
|
||||||
const toggleFavorite = async () => {
|
const toggleFavorite = async () => {
|
||||||
if (favLoading) return;
|
if (favLoading) return;
|
||||||
setFavLoading(true);
|
setFavLoading(true);
|
||||||
@@ -63,6 +98,38 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleTeamFavorite = async (teamKey: string, isHome: boolean) => {
|
||||||
|
const isTeamFav = isHome ? isHomeFav : isAwayFav;
|
||||||
|
const setLoading = isHome ? setHomeFavLoading : setAwayFavLoading;
|
||||||
|
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
|
||||||
|
const loading = isHome ? homeFavLoading : awayFavLoading;
|
||||||
|
|
||||||
|
if (loading) return;
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const newFavState = !isTeamFav;
|
||||||
|
try {
|
||||||
|
if (newFavState) {
|
||||||
|
await addFavorite({
|
||||||
|
teamId: Number(teamKey),
|
||||||
|
type: "team",
|
||||||
|
typeId: teamKey.toString(),
|
||||||
|
notify: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await removeFavorite({
|
||||||
|
type: "team",
|
||||||
|
typeId: teamKey.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setFav(newFavState);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Toggle team favorite error:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={["#521e10", "#0e0e10"]}
|
colors={["#521e10", "#0e0e10"]}
|
||||||
@@ -108,12 +175,25 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
|||||||
{/* Score Section */}
|
{/* Score Section */}
|
||||||
<View style={styles.scoreRow}>
|
<View style={styles.scoreRow}>
|
||||||
<View style={styles.teamInfo}>
|
<View style={styles.teamInfo}>
|
||||||
|
<View style={styles.teamLogoRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleTeamFavorite(match.homeTeamKey, true)}
|
||||||
|
disabled={homeFavLoading}
|
||||||
|
style={styles.starBtnLeft}
|
||||||
|
>
|
||||||
|
<IconSymbol
|
||||||
|
name={isHomeFav ? "star" : "star-outline"}
|
||||||
|
size={20}
|
||||||
|
color={isHomeFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
<View style={styles.logoContainer}>
|
<View style={styles.logoContainer}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: match.homeTeamLogo }}
|
source={{ uri: match.homeTeamLogo }}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
</View>
|
||||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||||
{match.eventHomeTeam}
|
{match.eventHomeTeam}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
@@ -133,12 +213,25 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.teamInfo}>
|
<View style={styles.teamInfo}>
|
||||||
|
<View style={styles.teamLogoRow}>
|
||||||
<View style={styles.logoContainer}>
|
<View style={styles.logoContainer}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: match.awayTeamLogo }}
|
source={{ uri: match.awayTeamLogo }}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleTeamFavorite(match.awayTeamKey, false)}
|
||||||
|
disabled={awayFavLoading}
|
||||||
|
style={styles.starBtnRight}
|
||||||
|
>
|
||||||
|
<IconSymbol
|
||||||
|
name={isAwayFav ? "star" : "star-outline"}
|
||||||
|
size={20}
|
||||||
|
color={isAwayFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||||
{match.eventAwayTeam}
|
{match.eventAwayTeam}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
@@ -202,13 +295,26 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
teamLogoRow: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
logoContainer: {
|
logoContainer: {
|
||||||
width: 70,
|
width: 70,
|
||||||
height: 70,
|
height: 70,
|
||||||
marginBottom: 10,
|
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
|
starBtnLeft: {
|
||||||
|
padding: 8,
|
||||||
|
marginRight: -4,
|
||||||
|
},
|
||||||
|
starBtnRight: {
|
||||||
|
padding: 8,
|
||||||
|
marginLeft: -4,
|
||||||
|
},
|
||||||
teamLogo: {
|
teamLogo: {
|
||||||
width: 60,
|
width: 60,
|
||||||
height: 60,
|
height: 60,
|
||||||
|
|||||||
@@ -431,6 +431,7 @@ export const fetchUserProfile = async (): Promise<UserProfile> => {
|
|||||||
|
|
||||||
export const addFavorite = async (request: FavoriteRequest): Promise<any> => {
|
export const addFavorite = async (request: FavoriteRequest): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
|
// console.log("Adding favorite with request:", request);
|
||||||
const response = await apiClient.post<ApiResponse<any>>(
|
const response = await apiClient.post<ApiResponse<any>>(
|
||||||
API_ENDPOINTS.FAVORITES,
|
API_ENDPOINTS.FAVORITES,
|
||||||
request
|
request
|
||||||
@@ -450,6 +451,7 @@ export const removeFavorite = async (request: {
|
|||||||
typeId: string;
|
typeId: string;
|
||||||
}): Promise<any> => {
|
}): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
|
console.log("Removing favorite with request:", request);
|
||||||
const response = await apiClient.delete<ApiResponse<any>>(
|
const response = await apiClient.delete<ApiResponse<any>>(
|
||||||
API_ENDPOINTS.FAVORITES,
|
API_ENDPOINTS.FAVORITES,
|
||||||
{ data: request }
|
{ data: request }
|
||||||
@@ -498,6 +500,7 @@ export const fetchFavorites = async (
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (response.data.code === 0) {
|
if (response.data.code === 0) {
|
||||||
|
console.log("Fetched favorites:", JSON.stringify(response.data.data));
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
throw new Error(response.data.message);
|
throw new Error(response.data.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user