fix the issue on here, after complete the match app crashed, also when click on view match history from match completed modal it should open match details info from persist store for current match, but for all previous match those will come from API call, also the select man of the match modal not open which need to fix"use client";import { useState, useEffect } from "react";import { View, Text, ScrollView, TouchableOpacity, Alert, Modal, Dimensions,} from "react-native";import { SafeAreaView } from "react-native-safe-area-context";import { Play, Target, RotateCcw, AlertTriangle, X, Send, Users, Trophy, Wifi, WifiOff, Award,} from "lucide-react-native";import { useCricketStore } from "../../store/cricketStore";import { useSubmitMatch, useHealthCheck } from "../../hooks/useApi";import ManOfTheMatchModal from "../../components/ManOfTheMatchModal";import { router } from "expo-router";const { width: screenWidth } = Dimensions.get("window");const isTablet = screenWidth > 768;export default function LiveScoringTab() { const { currentMatch, teams, players, striker, nonStriker, bowler, setStriker, setNonStriker, setBowler, swapBatsmen, clearBowler, addBall, undoLastBall, updatePlayer, switchInnings, completeMatch, updateMatch, savePreviousState, restorePreviousState, } = useCricketStore(); const [showWicketModal, setShowWicketModal] = useState(false); const [showMotmModal, setShowMotmModal] = useState(false); const [showSubmitModal, setShowSubmitModal] = useState(false); const [selectedMotm, setSelectedMotm] = useState(""); const [wicketType, setWicketType] = useState("bowled"); const [outBatsmanId, setOutBatsmanId] = useState(""); // API hooks const submitMatchMutation = useSubmitMatch(); const { data: isOnline } = useHealthCheck(); // Load persisted player selections when match changes useEffect(() => { if (currentMatch && (!striker || !nonStriker)) { const currentInnings = currentMatch.innings[currentMatch.currentInnings - 1]; if (currentInnings.currentBatsmanIds.length >= 2) { const strikerPlayer = players.find( (p) => p.id === currentInnings.currentBatsmanIds[0] ); const nonStrikerPlayer = players.find( (p) => p.id === currentInnings.currentBatsmanIds[1] ); if (strikerPlayer && !striker) setStriker(strikerPlayer.name); if (nonStrikerPlayer && !nonStriker) setNonStriker(nonStrikerPlayer.name); } if (currentInnings.currentBowlerId && !bowler) { const bowlerPlayer = players.find( (p) => p.id === currentInnings.currentBowlerId ); if (bowlerPlayer) setBowler(bowlerPlayer.name); } } }, [currentMatch, players, striker, nonStriker, bowler]); if (!currentMatch) { return ( <SafeAreaView className="flex-1 bg-slate-50"> <View className="bg-primary-500 px-5 py-4 pt-2.5"> <Text className="text-2xl font-bold text-white text-center"> Live Scoring </Text> <Text className="text-sm text-primary-100 text-center mt-1"> No active match </Text> </View> <View className="flex-1 justify-center items-center p-10"> <Play size={80} color="#D1D5DB" /> <Text className="text-2xl font-bold text-gray-600 mt-5 mb-2"> No Active Match </Text> <Text className="text-base text-gray-500 text-center mb-6 leading-6"> Start a new match from the Match Setup tab to begin scoring </Text> <TouchableOpacity className="bg-primary-500 rounded-3xl py-3.5 px-6 shadow-lg" onPress={() => router.push("/(tabs)/match-setup")} > <Text className="text-base font-semibold text-white"> Setup New Match </Text> </TouchableOpacity> </View> </SafeAreaView> ); } const battingTeam = teams.find( (team) => team.id === currentMatch.battingTeamId ); const bowlingTeam = teams.find( (team) => team.id === currentMatch.bowlingTeamId ); const currentInnings = currentMatch.innings[currentMatch.currentInnings - 1]; const battingPlayers = players.filter( (p) => p.teamId === currentMatch.battingTeamId && !p.isOut ); const bowlingPlayers = players.filter( (p) => p.teamId === currentMatch.bowlingTeamId ); const runButtons = [0, 1, 2, 3, 4, 6]; const extrasButtons = ["Wd", "Nb", "Lb", "B"]; // Get current bowler's legal balls in current over const getCurrentOverBalls = () => { if (!currentInnings.balls.length || !bowler) return 0; const bowlerPlayer = players.find((p) => p.name === bowler); if (!bowlerPlayer) return 0; // Count legal balls in current over by current bowler const totalLegalBalls = currentInnings.balls.filter( (ball) => !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball") ).length; const currentOverStart = Math.floor(totalLegalBalls / 6) * 6; const currentOverBalls = currentInnings.balls.slice(currentOverStart); return currentOverBalls.filter( (ball) => ball.bowlerId === bowlerPlayer.id && (!ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball")) ).length; }; // Check if current bowler can bowl more balls const canBowlerContinue = () => { return getCurrentOverBalls() < 6; }; const handleRunInput = (runValue, isExtra = false, extraType) => { if (!striker || !nonStriker || !bowler) { Alert.alert( "Selection Required", "Please select striker, non-striker and bowler first" ); return; } if (striker === nonStriker) { Alert.alert( "Invalid Selection", "Striker and non-striker cannot be the same player" ); return; } if ( !canBowlerContinue() && (!isExtra || (extraType !== "wide" && extraType !== "noball")) ) { Alert.alert( "Over Complete", "This bowler has completed 6 legal balls. Please select a new bowler." ); return; } const strikerPlayer = players.find((p) => p.name === striker); const nonStrikerPlayer = players.find((p) => p.name === nonStriker); const bowlerPlayer = players.find((p) => p.name === bowler); if (!strikerPlayer || !nonStrikerPlayer || !bowlerPlayer) { Alert.alert("Error", "Invalid player selection"); return; } const isLegalBall = !isExtra || (extraType !== "wide" && extraType !== "noball"); const currentOverBalls = currentInnings.totalBalls % 6; const ballNumber = isLegalBall ? currentOverBalls + 1 : currentOverBalls; const currentOver = Math.floor(currentInnings.totalBalls / 6) + 1; const newBall = { id: Date.now().toString(), over: currentOver, ballNumber: ballNumber, runs: runValue, extras: isExtra ? extraType === "wide" || extraType === "noball" ? 1 : 0 : 0, extrasType: extraType, isWicket: false, batsmanId: strikerPlayer.id, bowlerId: bowlerPlayer.id, nonStrikerId: nonStrikerPlayer.id, timestamp: new Date(), }; // Save previous state for undo savePreviousState(newBall); // Add ball to match addBall(currentMatch.id, newBall); // Handle strike rotation const shouldChangeStrike = runValue % 2 === 1 || (isLegalBall && (currentInnings.totalBalls + 1) % 6 === 0); if (shouldChangeStrike) { swapBatsmen(); } // Clear bowler at end of over if (isLegalBall && (currentInnings.totalBalls + 1) % 6 === 0) { clearBowler(); } // Check if target is achieved in second innings if (currentMatch.currentInnings === 2) { const extrasRuns = isExtra ? extraType === "wide" || extraType === "noball" ? 1 + runValue : runValue : 0; const newTotalRuns = currentInnings.totalRuns + runValue + extrasRuns; const target = currentMatch.innings[0].totalRuns + 1; if (newTotalRuns >= target) { setTimeout(() => { completeMatch(currentMatch.id, currentMatch.battingTeamId); setShowMotmModal(true); }, 1000); return; } } }; const handleExtrasInput = (extraType, runs = 1) => { if (!striker || !nonStriker || !bowler) { Alert.alert( "Selection Required", "Please select striker, non-striker and bowler first" ); return; } if (extraType === "wide" || extraType === "noball") { handleRunInput(runs - 1, true, extraType); } else { handleRunInput(runs, true, extraType); } }; const handleWicket = () => { if (!striker || !nonStriker || !bowler) { Alert.alert( "Selection Required", "Please select striker, non-striker and bowler first" ); return; } if (!canBowlerContinue()) { Alert.alert( "Over Complete", "This bowler has completed 6 legal balls. Please select a new bowler." ); return; } if (!outBatsmanId) { Alert.alert("Error", "Please select the batsman who is out"); return; } const outPlayer = players.find((p) => p.id === outBatsmanId); const bowlerPlayer = players.find((p) => p.name === bowler); if (!outPlayer || !bowlerPlayer) { Alert.alert("Error", "Invalid player selection"); return; } const currentOverBalls = currentInnings.totalBalls % 6; const currentOver = Math.floor(currentInnings.totalBalls / 6) + 1; const newBall = { id: Date.now().toString(), over: currentOver, ballNumber: currentOverBalls + 1, runs: 0, extras: 0, isWicket: true, wicketType: wicketType, batsmanId: outPlayer.id, bowlerId: bowlerPlayer.id, nonStrikerId: players.find((p) => p.name === nonStriker)?.id || "", timestamp: new Date(), }; // Save previous state for undo savePreviousState(newBall); // Add ball and mark player as out addBall(currentMatch.id, newBall); updatePlayer({ ...outPlayer, isOut: true }); // Reset striker/non-striker if they're out if (outPlayer.name === striker) { setStriker(""); } else if (outPlayer.name === nonStriker) { setNonStriker(""); } // Check if all out or overs complete const updatedWickets = currentInnings.totalWickets + 1; const oversComplete = Math.floor((currentInnings.totalBalls + 1) / 6) >= currentMatch.totalOvers; if (updatedWickets >= 10 || oversComplete) { if (currentMatch.currentInnings === 1) { setTimeout(() => { switchInnings(currentMatch.id); }, 1000); } else { setTimeout(() => { const target = currentMatch.innings[0].totalRuns + 1; const winner = currentInnings.totalRuns >= target ? currentMatch.battingTeamId : currentMatch.bowlingTeamId; completeMatch(currentMatch.id, winner); setShowMotmModal(true); }, 1000); } } // Clear bowler at end of over if ((currentInnings.totalBalls + 1) % 6 === 0) { clearBowler(); } setShowWicketModal(false); setOutBatsmanId(""); }; const handleUndo = () => { if (currentInnings.balls.length === 0) { Alert.alert("Error", "No balls to undo"); return; } Alert.alert( "Undo Last Ball", "Are you sure you want to undo the last ball?", [ { text: "Cancel", style: "cancel" }, { text: "Undo", onPress: () => { const lastBall = currentInnings.balls[currentInnings.balls.length - 1]; // If last ball was a wicket, restore the player if (lastBall.isWicket) { const outPlayer = players.find( (p) => p.id === lastBall.batsmanId ); if (outPlayer) { updatePlayer({ ...outPlayer, isOut: false }); } } // Undo the ball undoLastBall(currentMatch.id); // Restore previous state restorePreviousState(); }, }, ] ); }; const handleInningsSwitch = () => { if (currentMatch.status === "innings-break") { switchInnings(currentMatch.id); } }; const handleSubmitMatch = async () => { if (!selectedMotm) { Alert.alert("Error", "Please select Man of the Match first"); return; } try { const matchData = { match: { ...currentMatch, manOfTheMatch: selectedMotm }, teams: teams.filter( (t) => t.id === currentMatch.team1Id || t.id === currentMatch.team2Id ), players: players.filter((p) => teams.some( (t) => (t.id === currentMatch.team1Id || t.id === currentMatch.team2Id) && t.id === p.teamId ) ), }; await submitMatchMutation.mutateAsync(matchData); Alert.alert("Success", "Match data submitted successfully!"); setShowSubmitModal(false); } catch (error) { console.error("Error submitting match:", error); Alert.alert("Error", "Failed to submit match data. Please try again."); } }; const getCurrentOver = () => { if (!currentInnings.balls.length) return []; // Get balls from current over const totalLegalBalls = currentInnings.balls.filter( (ball) => !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball") ).length; const currentOverBalls = []; let legalBallsInCurrentOver = 0; // Go through balls from most recent backwards for (let i = currentInnings.balls.length - 1; i >= 0; i--) { const ball = currentInnings.balls[i]; // Count legal balls to determine over boundary if ( !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball") ) { if (legalBallsInCurrentOver >= 6) break; legalBallsInCurrentOver++; } currentOverBalls.unshift(ball); // Stop if we've collected enough balls for current over if (legalBallsInCurrentOver >= 6) break; } return currentOverBalls; }; const isPlayersSelected = striker && nonStriker && bowler; const getPlayerStats = (playerId, type) => { const playerBalls = currentInnings.balls.filter((ball) => type === "batting" ? ball.batsmanId === playerId : ball.bowlerId === playerId ); if (type === "batting") { const runs = playerBalls.reduce((sum, ball) => { // Only count runs scored by batsman (not extras like byes/leg-byes) if ( !ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye") ) { return sum + ball.runs; } return sum; }, 0); const balls = playerBalls.filter( (ball) => !ball.extrasType || ball.extrasType === "legbye" || ball.extrasType === "bye" ).length; const fours = playerBalls.filter( (ball) => ball.runs === 4 && (!ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye")) ).length; const sixes = playerBalls.filter( (ball) => ball.runs === 6 && (!ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye")) ).length; const isOut = playerBalls.some( (ball) => ball.isWicket && ball.batsmanId === playerId ); return { runs, balls, fours, sixes, isOut, strikeRate: balls > 0 ? (runs / balls) * 100 : 0, }; } else { const runs = playerBalls.reduce( (sum, ball) => sum + ball.runs + ball.extras, 0 ); const validBalls = playerBalls.filter( (ball) => !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball") ).length; const overs = Math.floor(validBalls / 6); const balls = validBalls % 6; const wickets = playerBalls.filter((ball) => ball.isWicket).length; const maidens = 0; // Calculate maidens logic here const economy = overs > 0 ? runs / overs : 0; return { runs, overs: `${overs}.${balls}`, wickets, maidens, economy }; } }; const getBowlingStats = () => { const bowlerStats = new Map(); currentInnings.balls.forEach((ball) => { const bowlerName = players.find((p) => p.id === ball.bowlerId)?.name || ""; if (!bowlerStats.has(bowlerName)) { bowlerStats.set(bowlerName, { overs: 0, runs: 0, wickets: 0, balls: 0, }); } const stats = bowlerStats.get(bowlerName); stats.runs += ball.runs + ball.extras; if (ball.isWicket) stats.wickets++; if ( !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball") ) { stats.balls++; } stats.overs = `${Math.floor(stats.balls / 6)}.${stats.balls % 6}`; }); return Array.from(bowlerStats.entries()); }; // Calculate required run rate for second innings const getRequiredRunRate = () => { if (currentMatch.currentInnings !== 2) return null; const target = currentMatch.innings[0].totalRuns + 1; const runsNeeded = target - currentInnings.totalRuns; const ballsRemaining = currentMatch.totalOvers * 6 - currentInnings.totalBalls; const oversRemaining = ballsRemaining / 6; return oversRemaining > 0 ? (runsNeeded / oversRemaining).toFixed(2) : "0.00"; }; if (currentMatch.status === "innings-break") { return ( <SafeAreaView className="flex-1 bg-slate-50"> <View className="bg-primary-500 px-5 py-4 pt-2.5"> <Text className="text-2xl font-bold text-white text-center"> Innings Break </Text> <Text className="text-sm text-primary-100 text-center mt-1"> First innings completed </Text> </View> <View className="flex-1 justify-center items-center p-5"> <View className="bg-white rounded-3xl p-8 w-full max-w-sm items-center shadow-2xl"> <Text className="text-xl font-bold text-primary-500 mb-6"> First Innings Complete </Text> <View className="items-center mb-6"> <Text className="text-lg font-semibold text-gray-600 mb-3"> {battingTeam?.name} </Text> <Text className="text-4xl font-bold text-primary-500 mb-2"> {currentInnings.totalRuns}/{currentInnings.totalWickets} </Text> <Text className="text-lg text-gray-500"> ({Math.floor(currentInnings.totalBalls / 6)}. {currentInnings.totalBalls % 6} overs) </Text> </View> <View className="items-center mb-8 p-5 bg-yellow-50 rounded-2xl w-full"> <Text className="text-base text-yellow-800 mb-2"> Target for{" "} {teams.find((t) => t.id !== currentMatch.battingTeamId)?.name} </Text> <Text className="text-2xl font-bold text-yellow-800"> {currentInnings.totalRuns + 1} runs </Text> </View> <TouchableOpacity className="bg-primary-500 rounded-2xl py-4 px-8 flex-row items-center shadow-lg" onPress={handleInningsSwitch} > <Play size={20} color="#FFFFFF" /> <Text className="text-lg font-semibold text-white ml-2"> Start Second Innings </Text> </TouchableOpacity> </View> </View> </SafeAreaView> ); } if (currentMatch.status === "completed") { const winnerTeam = teams.find((t) => t.id === currentMatch.winner); const motmPlayer = players.find((p) => p.id === currentMatch.manOfTheMatch); return ( <SafeAreaView className="flex-1 bg-slate-50"> <View className="bg-primary-500 px-5 py-4 pt-2.5 flex-row justify-between items-center"> <View className="flex-1"> <Text className="text-2xl font-bold text-white text-center"> Match Completed </Text> <Text className="text-sm text-primary-100 text-center mt-1"> Final result </Text> </View> <View className="p-1"> {isOnline ? ( <Wifi size={20} color="#10B981" /> ) : ( <WifiOff size={20} color="#EF4444" /> )} </View> </View> <ScrollView className="flex-1 p-4" showsVerticalScrollIndicator={false}> <View className="p-1"> <View className="bg-white rounded-3xl p-7 mb-6 shadow-2xl"> <Text className="text-3xl font-bold text-primary-500 text-center mb-6"> 🏆 Match Result </Text> <View className="bg-slate-50 rounded-2xl p-5 mb-6"> <View className="flex-row justify-between items-center mb-3"> <Text className="text-lg font-semibold text-gray-600 flex-1"> { teams.find((t) => t.id === currentMatch.innings[0].teamId) ?.name } </Text> <Text className="text-lg font-bold text-primary-500"> {currentMatch.innings[0].totalRuns}/ {currentMatch.innings[0].totalWickets}( {Math.floor(currentMatch.innings[0].totalBalls / 6)}. {currentMatch.innings[0].totalBalls % 6} ov) </Text> </View> {currentMatch.innings[1] && ( <View className="flex-row justify-between items-center mb-3"> <Text className="text-lg font-semibold text-gray-600 flex-1"> { teams.find( (t) => t.id === currentMatch.innings[1].teamId )?.name } </Text> <Text className="text-lg font-bold text-primary-500"> {currentMatch.innings[1].totalRuns}/ {currentMatch.innings[1].totalWickets}( {Math.floor(currentMatch.innings[1].totalBalls / 6)}. {currentMatch.innings[1].totalBalls % 6} ov) </Text> </View> )} </View> {winnerTeam && ( <View className="items-center mb-5 p-5 bg-green-50 rounded-2xl"> <Text className="text-2xl font-bold text-primary-500 mb-2"> 🎉 {winnerTeam.name} Won! </Text> {currentMatch.innings[1] && ( <Text className="text-base text-green-700"> {currentMatch.winner === currentMatch.innings[1].teamId ? `by ${ 10 - currentMatch.innings[1].totalWickets } wickets` : `by ${ currentMatch.innings[0].totalRuns - currentMatch.innings[1].totalRuns } runs`} </Text> )} </View> )} {motmPlayer && ( <View className="items-center p-4 bg-yellow-50 rounded-2xl"> <Text className="text-lg font-semibold text-yellow-800"> ⭐ Man of the Match: {motmPlayer.name} </Text> </View> )} </View> <View className="gap-4"> {/* Man of the Match Selection Button */} {!currentMatch.manOfTheMatch && ( <TouchableOpacity className="bg-yellow-500 rounded-2xl py-4 px-6 flex-row items-center justify-center shadow-lg" onPress={() => setShowMotmModal(true)} > <Award size={16} color="#FFFFFF" /> <Text className="text-lg font-semibold text-white ml-2"> Select Man of the Match </Text> </TouchableOpacity> )} {!submitMatchMutation.isSuccess ? ( <TouchableOpacity className={`rounded-2xl py-4 px-6 flex-row items-center justify-center shadow-lg ${ submitMatchMutation.isPending || !currentMatch.manOfTheMatch ? "bg-gray-400" : "bg-blue-500" }`} onPress={() => setShowSubmitModal(true)} disabled={ submitMatchMutation.isPending || !currentMatch.manOfTheMatch } > <Send size={16} color="#FFFFFF" /> <Text className="text-lg font-semibold text-white ml-2"> {submitMatchMutation.isPending ? "Submitting..." : "Submit to Database"} </Text> </TouchableOpacity> ) : ( <View className="bg-green-50 rounded-2xl py-4 px-6 items-center border-2 border-primary-500"> <Text className="text-lg font-semibold text-primary-500"> ✓ Submitted Successfully </Text> </View> )} <TouchableOpacity className="bg-gray-600 rounded-2xl py-4 px-6 flex-row items-center justify-center shadow-lg" onPress={() => router.push("/(tabs)/history")} > <Trophy size={16} color="#FFFFFF" /> <Text className="text-lg font-semibold text-white ml-2"> View Match History </Text> </TouchableOpacity> </View> </View> </ScrollView> {/* Submit Confirmation Modal */} <Modal visible={showSubmitModal} transparent animationType="slide" onRequestClose={() => setShowSubmitModal(false)} > <View className="flex-1 bg-black/60 justify-center items-center p-5"> <View className={`bg-white rounded-3xl p-6 w-full ${ isTablet ? "max-w-lg" : "max-w-sm" }`} > <View className="flex-row justify-between items-center mb-6"> <Text className="text-xl font-semibold text-gray-600"> Submit Match Data </Text> <TouchableOpacity onPress={() => setShowSubmitModal(false)}> <X size={20} color="#6B7280" /> </TouchableOpacity> </View> <Text className="text-base text-gray-500 text-center mb-6 leading-6"> Are you sure you want to submit this match data to the database? This action cannot be undone. </Text> <View className="flex-row gap-4"> <TouchableOpacity className="flex-1 bg-gray-100 rounded-2xl py-3.5 items-center" onPress={() => setShowSubmitModal(false)} > <Text className="text-base font-semibold text-gray-600"> Cancel </Text> </TouchableOpacity> <TouchableOpacity className="flex-1 bg-blue-500 rounded-2xl py-3.5 items-center shadow-lg" onPress={handleSubmitMatch} disabled={submitMatchMutation.isPending} > <Text className="text-base font-semibold text-white"> {submitMatchMutation.isPending ? "Submitting..." : "Submit"} </Text> </TouchableOpacity> </View> </View> </View> </Modal> </SafeAreaView> ); } return ( <SafeAreaView className="flex-1 bg-slate-50"> <View className="bg-primary-500 px-5 py-4 pt-2.5 flex-row justify-between items-center"> <View className="flex-1"> <Text className="text-2xl font-bold text-white text-center"> Live Match </Text> <Text className="text-sm text-primary-100 text-center mt-1"> {battingTeam?.shortName} vs {bowlingTeam?.shortName} •{" "} {currentMatch.totalOvers} overs </Text> </View> <View className="p-1"> {isOnline ? ( <Wifi size={20} color="#10B981" /> ) : ( <WifiOff size={20} color="#EF4444" /> )} </View> </View> <ScrollView className="flex-1 p-4" showsVerticalScrollIndicator={false} contentContainerStyle={isTablet && { paddingHorizontal: 32 }} > {/* Main Score Card */} <View className={`bg-white rounded-3xl p-6 mb-5 shadow-xl ${ isTablet ? "p-8" : "" }`} > <View className="flex-row justify-between items-center mb-5"> <View className="flex-1"> <Text className="text-xl font-semibold text-gray-600 mb-1.5"> {battingTeam?.name} </Text> <Text className="text-base text-gray-500"> {currentMatch.currentInnings === 1 ? "1st Innings" : "2nd Innings"} </Text> </View> <View className="items-end"> <Text className="text-4xl font-bold text-primary-500"> {currentInnings.totalRuns}/{currentInnings.totalWickets} </Text> <Text className="text-base text-gray-500 mt-1"> ({Math.floor(currentInnings.totalBalls / 6)}. {currentInnings.totalBalls % 6}/{currentMatch.totalOvers} ov) </Text> </View> </View> {/* Current Over Progress */} <View className="border-t border-gray-200 pt-5"> <Text className="text-base font-semibold text-gray-500 mb-3"> Current Over </Text> <View className="flex-row gap-2"> {getCurrentOver() .slice(-6) .map((ball, index) => ( <View key={index} className={`w-9 h-9 rounded-full justify-center items-center shadow-md ${ ball.isWicket ? "bg-red-500" : ball.extras > 0 ? "bg-orange-500" : "bg-primary-500" }`} > <Text className="text-sm font-bold text-white"> {ball.isWicket ? "W" : ball.extras > 0 ? `${ball.runs + ball.extras}*` : ball.runs} </Text> </View> ))} {Array.from({ length: Math.max(0, 6 - getCurrentOver().slice(-6).length), }).map((_, index) => ( <View key={`empty-${index}`} className="w-9 h-9 rounded-full bg-gray-200" /> ))} </View> </View> </View> {/* Target Display for Second Innings */} {currentMatch.currentInnings === 2 && ( <View className={`bg-white rounded-3xl p-6 mb-5 shadow-xl border-l-4 border-orange-500 ${ isTablet ? "p-8" : "" }`} > <View className="flex-row items-center mb-4"> <Target size={20} color="#F97316" /> <Text className="text-lg font-semibold text-orange-500 ml-2"> Target </Text> </View> <View className="flex-row justify-between items-center"> <Text className="text-3xl font-bold text-orange-500"> {currentMatch.innings[0].totalRuns + 1} </Text> <View className="items-end"> <Text className="text-base text-gray-500 mb-1"> Need{" "} {Math.max( 0, currentMatch.innings[0].totalRuns + 1 - currentInnings.totalRuns )}{" "} runs </Text> <Text className="text-base text-gray-500 mb-1"> in{" "} {Math.max( 0, currentMatch.totalOvers * 6 - currentInnings.totalBalls )}{" "} balls </Text> <Text className="text-base font-semibold text-orange-500"> RRR: {getRequiredRunRate() || "0.00"} </Text> </View> </View> </View> )} {/* Action Buttons */} <View className={`flex-row gap-4 mb-6 ${isTablet ? "justify-center" : ""}`} > <TouchableOpacity className={`bg-red-500 rounded-2xl py-3.5 px-5 flex-row items-center flex-1 justify-center shadow-lg ${ !isPlayersSelected ? "opacity-50 bg-gray-400" : "" }`} onPress={() => setShowWicketModal(true)} disabled={!isPlayersSelected} > <AlertTriangle size={16} color="#FFFFFF" /> <Text className="text-base font-semibold text-white ml-2"> Wicket </Text> </TouchableOpacity> <TouchableOpacity className={`bg-orange-500 rounded-2xl py-3.5 px-5 flex-row items-center flex-1 justify-center shadow-lg ${ currentInnings.balls.length === 0 ? "opacity-50 bg-gray-400" : "" }`} onPress={handleUndo} disabled={currentInnings.balls.length === 0} > <RotateCcw size={16} color="#FFFFFF" /> <Text className="text-base font-semibold text-white ml-2"> Undo </Text> </TouchableOpacity> </View> {/* Current Players Selection */} <View className="mb-6"> <View className="flex-row items-center mb-4"> <Users size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-600 ml-2"> Current Players </Text> </View> <View className={`bg-white rounded-2xl p-5 shadow-lg ${ isTablet ? "p-7" : "" }`} > <View className="mb-5"> <Text className="text-base font-semibold text-gray-500 mb-3"> Striker </Text> <ScrollView horizontal showsHorizontalScrollIndicator={false} className="flex-row" > {battingPlayers.map((player) => ( <TouchableOpacity key={player.id} className={`rounded-3xl py-2.5 px-4 mr-3 min-w-24 items-center shadow-sm ${ striker === player.name ? "bg-primary-500" : nonStriker === player.name ? "bg-gray-200 opacity-60" : "bg-gray-100" }`} onPress={() => setStriker(player.name)} disabled={nonStriker === player.name} > <Text className={`text-sm font-semibold ${ striker === player.name ? "text-white" : nonStriker === player.name ? "text-gray-400" : "text-gray-600" }`} > {player.name} </Text> </TouchableOpacity> ))} </ScrollView> </View> <View className="mb-5"> <Text className="text-base font-semibold text-gray-500 mb-3"> Non-Striker </Text> <ScrollView horizontal showsHorizontalScrollIndicator={false} className="flex-row" > {battingPlayers .filter((player) => striker !== player.name) .map((player) => ( <TouchableOpacity key={player.id} className={`rounded-3xl py-2.5 px-4 mr-3 min-w-24 items-center shadow-sm ${ nonStriker === player.name ? "bg-primary-500" : "bg-gray-100" }`} onPress={() => setNonStriker(player.name)} > <Text className={`text-sm font-semibold ${ nonStriker === player.name ? "text-white" : "text-gray-600" }`} > {player.name} </Text> </TouchableOpacity> ))} </ScrollView> </View> <View className="mb-5"> <Text className="text-base font-semibold text-gray-500 mb-3"> Bowler </Text> <ScrollView horizontal showsHorizontalScrollIndicator={false} className="flex-row" > {bowlingPlayers.map((player) => { const isCurrentBowler = bowler === player.name; const canSelectBowler = !isCurrentBowler || canBowlerContinue(); return ( <TouchableOpacity key={player.id} className={`rounded-3xl py-2.5 px-4 mr-3 min-w-24 items-center shadow-sm ${ isCurrentBowler ? "bg-primary-500" : !canSelectBowler ? "bg-gray-200 opacity-60" : "bg-gray-100" }`} onPress={() => { if (canSelectBowler) { setBowler(player.name); } }} disabled={!canSelectBowler} > <Text className={`text-sm font-semibold ${ isCurrentBowler ? "text-white" : !canSelectBowler ? "text-gray-400" : "text-gray-600" }`} > {player.name}{" "} {!canBowlerContinue() && isCurrentBowler ? "(6 balls)" : ""} </Text> </TouchableOpacity> ); })} </ScrollView> </View> </View> </View> {/* Runs Input */} <View className="mb-6"> <Text className="text-lg font-semibold text-gray-600 ml-2 mb-4"> Runs </Text> <View className={`flex-row flex-wrap gap-3 ${ isTablet ? "justify-center" : "" }`} > {runButtons.map((run, index) => ( <TouchableOpacity key={index} className={`bg-white rounded-2xl w-16 h-16 justify-center items-center border-2 shadow-lg ${ run === 4 || run === 6 ? "bg-primary-500 border-primary-500" : !isPlayersSelected ? "opacity-50 bg-gray-400 border-gray-400" : "border-gray-200" } ${isTablet ? "w-20 h-20" : ""}`} onPress={() => handleRunInput(run)} disabled={!isPlayersSelected} > <Text className={`text-xl font-bold ${ run === 4 || run === 6 ? "text-white" : "text-gray-600" }`} > {run} </Text> </TouchableOpacity> ))} </View> </View> {/* Extras */} <View className="mb-6"> <Text className="text-lg font-semibold text-gray-600 ml-2 mb-4"> Extras </Text> <View className={`flex-row flex-wrap gap-3 ${ isTablet ? "justify-center" : "" }`} > {extrasButtons.map((extra, index) => ( <TouchableOpacity key={index} className={`bg-orange-500 border-orange-500 rounded-2xl w-16 h-16 justify-center items-center border-2 shadow-lg ${ !isPlayersSelected ? "opacity-50 bg-gray-400 border-gray-400" : "" } ${isTablet ? "w-20 h-20" : ""}`} onPress={() => { if (extra === "Wd") handleExtrasInput("wide"); else if (extra === "Nb") handleExtrasInput("noball"); else if (extra === "B") handleExtrasInput("bye"); else if (extra === "Lb") handleExtrasInput("legbye"); }} disabled={!isPlayersSelected} > <Text className="text-base font-bold text-white">{extra}</Text> </TouchableOpacity> ))} </View> </View> {/* Current Batsmen Stats */} {striker && nonStriker && ( <View className="mb-6"> <Text className="text-lg font-semibold text-gray-600 ml-2 mb-4"> Batting Stats </Text> <View className={`bg-white rounded-2xl p-5 shadow-lg ${ isTablet ? "p-7" : "" }`} > <View className="flex-row justify-between items-center py-3 border-b border-gray-100"> <View className="flex-1"> <Text className="text-base font-semibold text-gray-600"> {striker} * </Text> <Text className="text-sm text-gray-500 mt-1"> ({players.find((p) => p.name === striker)?.role}) </Text> </View> <Text className="text-base font-semibold text-primary-500"> { getPlayerStats( players.find((p) => p.name === striker)?.id || "", "batting" ).runs } ( { getPlayerStats( players.find((p) => p.name === striker)?.id || "", "batting" ).balls } ) </Text> </View> <View className="flex-row justify-between items-center py-3"> <View className="flex-1"> <Text className="text-base font-semibold text-gray-600"> {nonStriker} </Text> <Text className="text-sm text-gray-500 mt-1"> ({players.find((p) => p.name === nonStriker)?.role}) </Text> </View> <Text className="text-base font-semibold text-primary-500"> { getPlayerStats( players.find((p) => p.name === nonStriker)?.id || "", "batting" ).runs } ( { getPlayerStats( players.find((p) => p.name === nonStriker)?.id || "", "batting" ).balls } ) </Text> </View> </View> </View> )} {/* Bowling Stats */} <View className="mb-6"> <Text className="text-lg font-semibold text-gray-600 ml-2 mb-4"> Bowling Stats </Text> <View className={`bg-white rounded-2xl p-5 shadow-lg ${ isTablet ? "p-7" : "" }`} > {getBowlingStats().map(([bowlerName, stats]) => ( <View key={bowlerName} className="flex-row justify-between items-center py-3 border-b border-gray-100" > <Text className="text-base font-semibold text-gray-600"> {bowlerName} </Text> <Text className="text-base text-gray-500"> {stats.overs} - {stats.runs} - {stats.wickets} </Text> </View> ))} </View> </View> </ScrollView> {/* Wicket Modal */} <Modal visible={showWicketModal} transparent animationType="slide" onRequestClose={() => setShowWicketModal(false)} > <View className="flex-1 bg-black/60 justify-center items-center p-5"> <View className={`bg-white rounded-3xl p-6 w-full max-h-4/5 ${ isTablet ? "max-w-lg p-8" : "max-w-sm" }`} > <View className="flex-row justify-between items-center mb-6"> <Text className="text-xl font-semibold text-gray-600"> Wicket Details </Text> <TouchableOpacity onPress={() => setShowWicketModal(false)}> <X size={20} color="#6B7280" /> </TouchableOpacity> </View> <Text className="text-base font-semibold text-gray-500 mb-3"> Batsman Out </Text> <View className="flex-row gap-3 mb-5"> {[striker, nonStriker].filter(Boolean).map((batsmanName) => { const batsman = players.find((p) => p.name === batsmanName); return ( <TouchableOpacity key={batsman?.id} className={`flex-1 rounded-3xl py-2.5 px-4 items-center ${ outBatsmanId === batsman?.id ? "bg-red-500" : "bg-gray-100" }`} onPress={() => setOutBatsmanId(batsman?.id || "")} > <Text className={`text-base font-semibold ${ outBatsmanId === batsman?.id ? "text-white" : "text-gray-600" }`} > {batsmanName} </Text> </TouchableOpacity> ); })} </View> <Text className="text-base font-semibold text-gray-500 mb-3"> Wicket Type </Text> <View className="flex-row flex-wrap gap-2 mb-6"> {[ "bowled", "caught", "lbw", "runout", "stumped", "hitwicket", ].map((type) => ( <TouchableOpacity key={type} className={`rounded-2xl py-2 px-3 ${ wicketType === type ? "bg-red-500" : "bg-gray-100" }`} onPress={() => setWicketType(type)} > <Text className={`text-sm font-semibold ${ wicketType === type ? "text-white" : "text-gray-600" }`} > {type.charAt(0).toUpperCase() + type.slice(1)} </Text> </TouchableOpacity> ))} </View> <TouchableOpacity className="bg-red-500 rounded-2xl py-3.5 items-center shadow-lg" onPress={handleWicket} > <Text className="text-lg font-semibold text-white"> Confirm Wicket </Text> </TouchableOpacity> </View> </View> </Modal> {/* Man of the Match Modal */} <ManOfTheMatchModal visible={showMotmModal} onClose={() => setShowMotmModal(false)} match={currentMatch} players={players} teams={teams} selectedMotm={selectedMotm} onSelectMotm={setSelectedMotm} onConfirm={() => { if (selectedMotm) { updateMatch({ ...currentMatch, manOfTheMatch: selectedMotm, status: "completed", }); setShowMotmModal(false); } }} /> </SafeAreaView> );}import { create } from "zustand";import { persist, createJSONStorage } from "zustand/middleware";import AsyncStorage from "@react-native-async-storage/async-storage";const initialState = { teams: [ { id: "1", name: "Mumbai Indians", shortName: "MI", color: "#004ba0", createdAt: new Date(), }, { id: "2", name: "Chennai Super Kings", shortName: "CSK", color: "#ffff00", createdAt: new Date(), }, ], players: [ // Mumbai Indians Players { id: "mi1", name: "Rohit Sharma", teamId: "1", role: "batsman" }, { id: "mi2", name: "Ishan Kishan", teamId: "1", role: "wicketkeeper" }, { id: "mi3", name: "Suryakumar Yadav", teamId: "1", role: "batsman" }, { id: "mi4", name: "Tilak Varma", teamId: "1", role: "batsman" }, { id: "mi5", name: "Hardik Pandya", teamId: "1", role: "all-rounder" }, { id: "mi6", name: "Tim David", teamId: "1", role: "batsman" }, { id: "mi7", name: "Krunal Pandya", teamId: "1", role: "all-rounder" }, { id: "mi8", name: "Jasprit Bumrah", teamId: "1", role: "bowler" }, { id: "mi9", name: "Trent Boult", teamId: "1", role: "bowler" }, { id: "mi10", name: "Rahul Chahar", teamId: "1", role: "bowler" }, { id: "mi11", name: "Arjun Tendulkar", teamId: "1", role: "all-rounder" }, // Chennai Super Kings Players { id: "csk1", name: "MS Dhoni", teamId: "2", role: "wicketkeeper" }, { id: "csk2", name: "Ruturaj Gaikwad", teamId: "2", role: "batsman" }, { id: "csk3", name: "Devon Conway", teamId: "2", role: "batsman" }, { id: "csk4", name: "Ajinkya Rahane", teamId: "2", role: "batsman" }, { id: "csk5", name: "Shivam Dube", teamId: "2", role: "all-rounder" }, { id: "csk6", name: "Ravindra Jadeja", teamId: "2", role: "all-rounder" }, { id: "csk7", name: "Moeen Ali", teamId: "2", role: "all-rounder" }, { id: "csk8", name: "Deepak Chahar", teamId: "2", role: "bowler" }, { id: "csk9", name: "Tushar Deshpande", teamId: "2", role: "bowler" }, { id: "csk10", name: "Mustafizur Rahman", teamId: "2", role: "bowler" }, { id: "csk11", name: "Maheesh Theekshana", teamId: "2", role: "bowler" }, ], matches: [], currentMatch: null, striker: "", nonStriker: "", bowler: "", actionHistory: [], previousState: null,};export const useCricketStore = create( persist( (set, get) => ({ ...initialState, // Team actions addTeam: (team) => set((state) => ({ teams: [...state.teams, team], })), updateTeam: (updatedTeam) => set((state) => ({ teams: state.teams.map((team) => team.id === updatedTeam.id ? updatedTeam : team ), })), deleteTeam: (teamId) => set((state) => ({ teams: state.teams.filter((team) => team.id !== teamId), players: state.players.filter((player) => player.teamId !== teamId), })), // Player actions addPlayer: (player) => set((state) => ({ players: [...state.players, player], })), updatePlayer: (updatedPlayer) => set((state) => ({ players: state.players.map((player) => player.id === updatedPlayer.id ? updatedPlayer : player ), })), deletePlayer: (playerId) => set((state) => ({ players: state.players.filter((player) => player.id !== playerId), })), // Match actions startMatch: (match) => set(() => ({ matches: [...get().matches, match], currentMatch: match, striker: "", nonStriker: "", bowler: "", actionHistory: [], })), updateMatch: (updatedMatch) => set((state) => ({ matches: state.matches.map((match) => match.id === updatedMatch.id ? updatedMatch : match ), currentMatch: state.currentMatch?.id === updatedMatch.id ? updatedMatch : state.currentMatch, })), setCurrentMatch: (match) => set(() => ({ currentMatch: match, })), // Player selection actions setStriker: (playerName) => set(() => ({ striker: playerName, })), setNonStriker: (playerName) => set(() => ({ nonStriker: playerName, })), setBowler: (playerName) => set(() => ({ bowler: playerName, })), swapBatsmen: () => set((state) => ({ striker: state.nonStriker, nonStriker: state.striker, })), clearBowler: () => set(() => ({ bowler: "", })), // Ball actions addBall: (matchId, ball) => set((state) => { const updatedMatches = state.matches.map((match) => { if (match.id === matchId) { const currentInnings = match.innings[match.currentInnings - 1]; const isLegalBall = !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball"); // Calculate total runs to add to team score let totalRunsToAdd = ball.runs; // Add extras to total runs if (ball.extrasType === "wide" || ball.extrasType === "noball") { totalRunsToAdd += 1; // 1 extra run for wide/no-ball plus any additional runs } else if ( ball.extrasType === "legbye" || ball.extrasType === "bye" ) { // For leg-byes and byes, runs count towards team but not batsman totalRunsToAdd = ball.runs; } const newTotalBalls = currentInnings.totalBalls + (isLegalBall ? 1 : 0); const newTotalOvers = Math.floor(newTotalBalls / 6); const newTotalWickets = ball.isWicket ? currentInnings.totalWickets + 1 : currentInnings.totalWickets; const updatedInnings = { ...currentInnings, balls: [...currentInnings.balls, ball], totalRuns: currentInnings.totalRuns + totalRunsToAdd, totalBalls: newTotalBalls, totalOvers: newTotalOvers, totalWickets: newTotalWickets, currentBatsmanIds: [ball.batsmanId, ball.nonStrikerId], currentBowlerId: ball.bowlerId, }; // Check if innings is complete const isInningsComplete = newTotalWickets >= 10 || newTotalOvers >= match.totalOvers; // Check if target is achieved in second innings let targetAchieved = false; if (match.currentInnings === 2) { const target = match.innings[0].totalRuns + 1; targetAchieved = currentInnings.totalRuns + totalRunsToAdd >= target; } let newStatus = match.status; if (isInningsComplete || targetAchieved) { if (match.currentInnings === 1) { newStatus = "innings-break"; } else { newStatus = "completed"; } } return { ...match, innings: match.innings.map((innings, index) => index === match.currentInnings - 1 ? updatedInnings : innings ), status: newStatus, winner: targetAchieved ? match.battingTeamId : newStatus === "completed" ? match.winner : undefined, }; } return match; }); return { matches: updatedMatches, currentMatch: state.currentMatch?.id === matchId ? updatedMatches.find((m) => m.id === matchId) || null : state.currentMatch, actionHistory: [ ...state.actionHistory, { type: "ADD_BALL", payload: { matchId, ball }, timestamp: new Date(), }, ], }; }), undoLastBall: (matchId) => set((state) => { const matchToUndo = state.matches.find((m) => m.id === matchId); if (!matchToUndo) return state; const currentInningsUndo = matchToUndo.innings[matchToUndo.currentInnings - 1]; if (currentInningsUndo.balls.length === 0) return state; const lastBall = currentInningsUndo.balls[currentInningsUndo.balls.length - 1]; const isValidBallUndo = !lastBall.extrasType || (lastBall.extrasType !== "wide" && lastBall.extrasType !== "noball"); // Calculate runs to subtract let runsToSubtract = lastBall.runs; if ( lastBall.extrasType === "wide" || lastBall.extrasType === "noball" ) { runsToSubtract += 1; // Include the extra run } const undoMatches = state.matches.map((match) => { if (match.id === matchId) { const updatedInningsUndo = { ...currentInningsUndo, balls: currentInningsUndo.balls.slice(0, -1), totalRuns: currentInningsUndo.totalRuns - runsToSubtract, totalBalls: currentInningsUndo.totalBalls - (isValidBallUndo ? 1 : 0), totalOvers: Math.floor( (currentInningsUndo.totalBalls - (isValidBallUndo ? 1 : 0)) / 6 ), totalWickets: lastBall.isWicket ? currentInningsUndo.totalWickets - 1 : currentInningsUndo.totalWickets, }; return { ...match, innings: match.innings.map((innings, index) => index === match.currentInnings - 1 ? updatedInningsUndo : innings ), status: "live", }; } return match; }); return { matches: undoMatches, currentMatch: state.currentMatch?.id === matchId ? undoMatches.find((m) => m.id === matchId) || null : state.currentMatch, }; }), switchInnings: (matchId) => set((state) => { const matchToSwitch = state.matches.find((m) => m.id === matchId); if (!matchToSwitch) return state; // Reset all players' out status for the new batting team const newBattingTeamId = matchToSwitch.battingTeamId === matchToSwitch.team1Id ? matchToSwitch.team2Id : matchToSwitch.team1Id; const newBattingTeamPlayerIds = state.players .filter((p) => p.teamId === newBattingTeamId) .map((p) => p.id); const resetPlayers = state.players.map((player) => newBattingTeamPlayerIds.includes(player.id) ? { ...player, isOut: false } : player ); const switchedMatches = state.matches.map((match) => { if (match.id === matchId) { const newBowlingTeamId = match.bowlingTeamId === match.team1Id ? match.team2Id : match.team1Id; const newInnings = { id: Date.now().toString() + "_2", teamId: newBattingTeamId, totalRuns: 0, totalWickets: 0, totalOvers: 0, totalBalls: 0, balls: [], currentBatsmanIds: [], currentBowlerId: "", currentNonStrikerId: "", }; return { ...match, battingTeamId: newBattingTeamId, bowlingTeamId: newBowlingTeamId, currentInnings: 2, innings: [...match.innings, newInnings], status: "live", }; } return match; }); return { players: resetPlayers, matches: switchedMatches, currentMatch: state.currentMatch?.id === matchId ? switchedMatches.find((m) => m.id === matchId) || null : state.currentMatch, striker: "", nonStriker: "", bowler: "", }; }), completeMatch: (matchId, winner) => set((state) => { const completedMatches = state.matches.map((match) => { if (match.id === matchId) { return { ...match, status: "completed", winner: winner, }; } return match; }); return { matches: completedMatches, currentMatch: state.currentMatch?.id === matchId ? completedMatches.find((m) => m.id === matchId) || null : state.currentMatch, }; }), // Undo functionality savePreviousState: (ball) => set((state) => ({ previousState: { striker: state.striker, nonStriker: state.nonStriker, bowler: state.bowler, ball: ball, }, })), restorePreviousState: () => set((state) => { if (!state.previousState) return state; return { striker: state.previousState.striker, nonStriker: state.previousState.nonStriker, bowler: state.previousState.bowler, previousState: null, }; }), }), { name: "cricket-store", storage: createJSONStorage(() => AsyncStorage), } ));"use client";import { useMemo } from "react";import { View, Text, ScrollView, TouchableOpacity, Modal, Dimensions,} from "react-native";import { X, Award, TrendingUp, Target, Zap } from "lucide-react-native";import { calculatePerformanceScore } from "../utils/performance";const { width: screenWidth, height: screenHeight } = Dimensions.get("window");const isTablet = screenWidth > 768;export default function ManOfTheMatchModal({ visible, onClose, match, players, teams, selectedMotm, onSelectMotm, onConfirm,}) { // Calculate performance scores and suggestions const playerSuggestions = useMemo(() => { if (!match.innings || match.innings.length === 0) return []; const suggestions = players .filter((player) => teams.some( (team) => (team.id === match.team1Id || team.id === match.team2Id) && team.id === player.teamId ) ) .map((player) => { const performanceData = calculatePerformanceScore(player, match); return { player, ...performanceData, }; }) .filter((suggestion) => suggestion.totalScore > 0) .sort((a, b) => b.totalScore - a.totalScore) .slice(0, 6); // Top 6 performers return suggestions; }, [match, players, teams]); const getPerformanceIcon = (category) => { switch (category) { case "batting": return <Target size={16} color="#F59E0B" />; case "bowling": return <Zap size={16} color="#3B82F6" />; case "all-round": return <TrendingUp size={16} color="#10B981" />; default: return <Award size={16} color="#6B7280" />; } }; const getPerformanceColor = (category) => { switch (category) { case "batting": return "#F59E0B"; case "bowling": return "#3B82F6"; case "all-round": return "#10B981"; default: return "#6B7280"; } }; const formatPerformanceText = (suggestion) => { const parts = []; if (suggestion.battingStats.runs > 0) { parts.push( `${suggestion.battingStats.runs}(${suggestion.battingStats.balls})` ); } if (suggestion.bowlingStats.wickets > 0) { parts.push( `${suggestion.bowlingStats.wickets}/${suggestion.bowlingStats.runs}` ); } return parts.join(" • ") || "Fielding contribution"; }; return ( <Modal visible={visible} transparent animationType="slide" onRequestClose={onClose} > <View className="flex-1 bg-black/70 justify-center items-center p-4"> <View className={`bg-white rounded-3xl w-full shadow-2xl ${ isTablet ? "max-w-2xl" : "max-w-lg" }`} style={{ maxHeight: screenHeight * 0.9 }} > {/* Header */} <View className="flex-row justify-between items-center p-6 pb-4 border-b border-gray-100"> <View className="flex-row items-center"> <Award size={24} color="#F59E0B" /> <Text className="text-2xl font-bold text-gray-600 ml-3"> Man of the Match </Text> </View> <TouchableOpacity onPress={onClose} className="p-2 rounded-3xl bg-gray-50" > <X size={24} color="#6B7280" /> </TouchableOpacity> </View> {/* Match Info */} <View className="px-5 py-4 bg-slate-50 border-b border-gray-200"> <Text className="text-base font-semibold text-gray-600 text-center mb-1"> {teams.find((t) => t.id === match.team1Id)?.name} vs{" "} {teams.find((t) => t.id === match.team2Id)?.name} </Text> {match.winner && ( <Text className="text-sm text-primary-500 text-center font-medium"> Winner: {teams.find((t) => t.id === match.winner)?.name} </Text> )} </View> {/* Performance-based Suggestions */} <View className="p-5 pb-4" style={{ maxHeight: screenHeight * 0.4 }}> <Text className="text-lg font-bold text-gray-600 mb-1"> 🎯 Top Performers </Text> <Text className="text-sm text-gray-500 mb-4"> Based on match performance </Text> <ScrollView className="flex-1" showsVerticalScrollIndicator={false} contentContainerStyle={{ gap: 12 }} > {playerSuggestions.map((suggestion, index) => ( <TouchableOpacity key={suggestion.player.id} className={`bg-white rounded-2xl p-4 border-2 shadow-sm ${ selectedMotm === suggestion.player.id ? "border-yellow-500 bg-yellow-50" : index === 0 ? "border-green-500 bg-green-50" : "border-gray-200" } ${isTablet ? "p-5" : ""}`} onPress={() => onSelectMotm(suggestion.player.id)} > <View className="flex-row justify-between items-start mb-3"> <View className="flex-1"> <View className="flex-row items-center mb-1"> <Text className={`text-lg font-bold ${ selectedMotm === suggestion.player.id ? "text-yellow-600" : "text-gray-600" }`} > {suggestion.player.name} </Text> {index === 0 && ( <View className="bg-green-500 rounded-2xl px-2 py-0.5 ml-2"> <Text className="text-xs font-bold text-white"> TOP </Text> </View> )} </View> <View className="flex-row items-center"> <Text className="text-sm font-semibold text-gray-500"> { teams.find((t) => t.id === suggestion.player.teamId) ?.shortName } </Text> <Text className="text-sm text-gray-400 ml-1"> • {suggestion.player.role} </Text> </View> </View> <View className="items-center"> <View className="w-8 h-8 rounded-2xl justify-center items-center mb-1" style={{ backgroundColor: `${getPerformanceColor( suggestion.category )}20`, }} > {getPerformanceIcon(suggestion.category)} </View> <Text className="text-base font-bold text-gray-600"> {suggestion.totalScore.toFixed(0)} </Text> </View> </View> <View className="mb-3"> <Text className="text-base font-semibold text-primary-500 mb-1"> {formatPerformanceText(suggestion)} </Text> <Text className="text-sm text-gray-500 leading-5"> {suggestion.reason} </Text> </View> {/* Performance Breakdown */} <View className="flex-row flex-wrap gap-2"> {suggestion.battingStats.runs > 0 && ( <View className="bg-gray-100 rounded-3xl px-2.5 py-1"> <Text className="text-xs font-semibold text-gray-500"> {suggestion.battingStats.runs} runs </Text> </View> )} {suggestion.bowlingStats.wickets > 0 && ( <View className="bg-gray-100 rounded-3xl px-2.5 py-1"> <Text className="text-xs font-semibold text-gray-500"> {suggestion.bowlingStats.wickets} wkts </Text> </View> )} {suggestion.battingStats.strikeRate > 0 && ( <View className="bg-gray-100 rounded-3xl px-2.5 py-1"> <Text className="text-xs font-semibold text-gray-500"> SR: {suggestion.battingStats.strikeRate.toFixed(1)} </Text> </View> )} {suggestion.bowlingStats.economy > 0 && ( <View className="bg-gray-100 rounded-3xl px-2.5 py-1"> <Text className="text-xs font-semibold text-gray-500"> Eco: {suggestion.bowlingStats.economy.toFixed(1)} </Text> </View> )} </View> </TouchableOpacity> ))} </ScrollView> </View> {/* All Players List */} <View className="p-5 pt-4 border-t border-gray-100"> <Text className="text-lg font-bold text-gray-600 mb-3"> 👥 All Players </Text> <ScrollView horizontal showsHorizontalScrollIndicator={false} className="flex-row" contentContainerStyle={{ gap: 12, paddingRight: 20 }} > {players .filter((player) => teams.some( (team) => (team.id === match.team1Id || team.id === match.team2Id) && team.id === player.teamId ) ) .map((player) => ( <TouchableOpacity key={player.id} className={`rounded-3xl px-4 py-2.5 border items-center min-w-24 ${ selectedMotm === player.id ? "bg-yellow-500 border-yellow-500" : "bg-gray-50 border-gray-200" }`} onPress={() => onSelectMotm(player.id)} > <Text className={`text-sm font-semibold mb-0.5 ${ selectedMotm === player.id ? "text-white" : "text-gray-600" }`} > {player.name} </Text> <Text className={`text-xs ${ selectedMotm === player.id ? "text-yellow-100" : "text-gray-500" }`} > {teams.find((t) => t.id === player.teamId)?.shortName} </Text> </TouchableOpacity> ))} </ScrollView> </View> {/* Action Buttons */} <View className="flex-row gap-4 p-6 pt-5 border-t border-gray-100"> <TouchableOpacity className="flex-1 bg-gray-50 rounded-2xl py-4 items-center border border-gray-200" onPress={onClose} > <Text className="text-base font-semibold text-gray-500"> Cancel </Text> </TouchableOpacity> <TouchableOpacity className={`flex-2 rounded-2xl py-4 flex-row items-center justify-center shadow-lg ${ !selectedMotm ? "bg-gray-400" : "bg-yellow-500" }`} onPress={onConfirm} disabled={!selectedMotm} > <Award size={16} color="#FFFFFF" /> <Text className="text-base font-semibold text-white ml-2"> Confirm Selection </Text> </TouchableOpacity> </View> </View> </View> </Modal> );}export const calculatePerformanceScore = (player, match) => { let totalScore = 0 let battingStats = { runs: 0, balls: 0, strikeRate: 0, fours: 0, sixes: 0 } let bowlingStats = { wickets: 0, runs: 0, economy: 0, overs: 0 } let category = "fielding" let reason = "" // Calculate batting performance match.innings.forEach((innings) => { const playerBalls = innings.balls?.filter((ball) => ball.batsmanId === player.id) || [] if (playerBalls.length > 0) { const runs = playerBalls.reduce((sum, ball) => { if (!ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye")) { return sum + ball.runs } return sum }, 0) const balls = playerBalls.filter( (ball) => !ball.extrasType || ball.extrasType === "legbye" || ball.extrasType === "bye", ).length const fours = playerBalls.filter( (ball) => ball.runs === 4 && (!ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye")), ).length const sixes = playerBalls.filter( (ball) => ball.runs === 6 && (!ball.extrasType || (ball.extrasType !== "bye" && ball.extrasType !== "legbye")), ).length battingStats = { runs, balls, strikeRate: balls > 0 ? (runs / balls) * 100 : 0, fours, sixes, } // Batting score calculation let battingScore = runs * 1.5 // Base runs score if (balls > 0) { const strikeRate = (runs / balls) * 100 if (strikeRate > 150) battingScore += 20 else if (strikeRate > 120) battingScore += 10 else if (strikeRate < 80) battingScore -= 10 } battingScore += fours * 2 + sixes * 4 // Boundary bonus totalScore += battingScore } }) // Calculate bowling performance match.innings.forEach((innings) => { const playerBalls = innings.balls?.filter((ball) => ball.bowlerId === player.id) || [] if (playerBalls.length > 0) { const runs = playerBalls.reduce((sum, ball) => sum + ball.runs + (ball.extras || 0), 0) const wickets = playerBalls.filter((ball) => ball.isWicket).length const validBalls = playerBalls.filter( (ball) => !ball.extrasType || (ball.extrasType !== "wide" && ball.extrasType !== "noball"), ).length const overs = validBalls / 6 const economy = overs > 0 ? runs / overs : 0 bowlingStats = { wickets, runs, economy, overs, } // Bowling score calculation let bowlingScore = wickets * 25 // Base wicket score if (overs > 0) { if (economy < 6) bowlingScore += 15 else if (economy < 8) bowlingScore += 5 else if (economy > 12) bowlingScore -= 10 } totalScore += bowlingScore } }) // Determine category and reason if (battingStats.runs > 0 && bowlingStats.wickets > 0) { category = "all-round" reason = `Excellent all-round performance with ${battingStats.runs} runs and ${bowlingStats.wickets} wickets` } else if (battingStats.runs >= 30 || battingStats.strikeRate > 140) { category = "batting" if (battingStats.runs >= 50) { reason = `Outstanding batting performance with ${battingStats.runs} runs at strike rate ${battingStats.strikeRate.toFixed(1)}` } else { reason = `Solid batting contribution with ${battingStats.runs} runs` } } else if (bowlingStats.wickets >= 2 || bowlingStats.economy < 7) { category = "bowling" if (bowlingStats.wickets >= 3) { reason = `Exceptional bowling figures with ${bowlingStats.wickets} wickets` } else { reason = `Good bowling performance with ${bowlingStats.wickets} wickets and economy ${bowlingStats.economy.toFixed(1)}` } } else { reason = "Contributed to team performance" } return { totalScore, battingStats, bowlingStats, category, reason, }}import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"import axios from "axios"const API_BASE_URL = process.env.EXPO_PUBLIC_API_URL || "http://localhost:3001/api"const api = axios.create({ baseURL: API_BASE_URL, timeout: 10000,})// Health check hookexport const useHealthCheck = () => { return useQuery({ queryKey: ["health"], queryFn: async () => { try { await api.get("/health") return true } catch (error) { return false } }, refetchInterval: 30000, // Check every 30 seconds retry: false, })}// Matches hooksexport const useMatches = (page = 1, limit = 20) => { return useQuery({ queryKey: ["matches", page, limit], queryFn: async () => { const response = await api.get(`/matches?page=${page}&limit=${limit}`) return response.data }, staleTime: 5 * 60 * 1000, // 5 minutes })}export const useSubmitMatch = () => { const queryClient = useQueryClient() return useMutation({ mutationFn: async (matchData) => { const response = await api.post("/matches", matchData) return response.data }, onSuccess: () => { // Invalidate matches query to refetch data queryClient.invalidateQueries({ queryKey: ["matches"] }) }, })}// Teams hooksexport const useTeams = () => { return useQuery({ queryKey: ["teams"], queryFn: async () => { const response = await api.get("/teams") return response.data }, })}// Players hooksexport const usePlayers = () => { return useQuery({ queryKey: ["players"], queryFn: async () => { const response = await api.get("/players") return response.data }, })}
Loading...
WARN StatusBar backgroundColor is not supported with edge-to-edge enabled. Render a view under the status bar to change its background. ERROR The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization for more details. WARN StatusBar backgroundColor is not supported with edge-to-edge enabled. Render a view under the status bar to change its background. ERROR Warning: Error: Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.this is root layout"use client";import { Stack } from "expo-router";import { StatusBar } from "expo-status-bar";import { QueryClient, QueryClientProvider } from "@tanstack/react-query";import { useFrameworkReady } from "../hooks/useFrameworkReady";import { useState } from "react";import "../assets/css/global.css";export default function RootLayout() {useFrameworkReady();// Create a clientconst [queryClient] = useState( () =>new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 10 * 60 * 1000, // 10 minutes retry: 3,retryDelay: (attemptIndex) =>Math.min(1000 * 2 ** attemptIndex, 30000), }, mutations: { retry: 1, }, }, }) );return (<QueryClientProvider client={queryClient}> <Stack screenOptions={{ headerShown: false }}> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <Stack.Screen name="+not-found" /> </Stack> <StatusBar style="light" backgroundColor="#16A34A" /> </QueryClientProvider> );}this is tab layoutimport { Tabs } from "expo-router"import { Users, Play, Trophy, History } from "lucide-react-native"export default function TabLayout() {return (<TabsscreenOptions={{ headerShown: false, tabBarStyle: { backgroundColor: "#FFFFFF", borderTopWidth: 1, borderTopColor: "#E5E7EB", height: 80, paddingBottom: 20, paddingTop: 10, }, tabBarActiveTintColor: "#16A34A", tabBarInactiveTintColor: "#6B7280", tabBarLabelStyle: { fontSize: 12, fontWeight: "600", }, }}> <Tabs.Screenname="index"options={{ title: "Teams",tabBarIcon: ({ size, color }) => <Users size={size} color={color} />, }}/> <Tabs.Screenname="match-setup"options={{ title: "New Match",tabBarIcon: ({ size, color }) => <Play size={size} color={color} />, }}/> <Tabs.Screenname="live-scoring"options={{ title: "Live Score",tabBarIcon: ({ size, color }) => <Trophy size={size} color={color} />, }}/> <Tabs.Screenname="history"options={{ title: "History",tabBarIcon: ({ size, color }) => <History size={size} color={color} />, }}/> </Tabs> )}this is history.jsx under tabs"use client";import { useState } from "react";import {View,Text,ScrollView,TouchableOpacity,Modal,Dimensions,} from "react-native";import { SafeAreaView } from "react-native-safe-area-context";import { Calendar, Trophy, Clock, X, Award } from "lucide-react-native";import { useMatches } from "../../hooks/useApi";const { width: screenWidth } = Dimensions.get("window");const isTablet = screenWidth > 768;export default function HistoryTab() {const [selectedMatch, setSelectedMatch] = useState(null);const [showMatchDetails, setShowMatchDetails] = useState(false);const { data: matchesData, isLoading, error } = useMatches(1, 50);const formatDate = (dateString) => {const date = new Date(dateString);return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", }); };const openMatchDetails = (match) => {setSelectedMatch(match);setShowMatchDetails(true); };const closeMatchDetails = () => {setShowMatchDetails(false);setSelectedMatch(null); };const renderMatchCard = (match) => (<TouchableOpacitykey={match.id}className="bg-white rounded-xl p-5 shadow-md shadow-black/5 mb-4"onPress={() => openMatchDetails(match)}> <View className="flex-row justify-between items-center mb-4"> <View className="flex-row items-center flex-1"> <Text className="text-base font-semibold text-gray-900"> {match.team1Name} </Text> <Text className="text-sm text-gray-500 mx-2">vs</Text> <Text className="text-base font-semibold text-gray-900"> {match.team2Name} </Text> </View> <View className="flex-row items-center"> <Calendar size={14} color="#6B7280" /> <Text className="text-sm text-gray-500 ml-2"> {formatDate(match.date)} </Text> </View> </View> <View className="mb-3"> {match.innings.map((innings, index) => (<View key={index} className="mb-1"> <Text className="text-base font-semibold text-green-600"> {innings.battingTeam}: {innings.totalRuns}/{innings.totalWickets} <Text className="text-sm font-normal text-gray-500"> {" "} ({Math.floor(innings.totalBalls / 6)}.{innings.totalBalls % 6}{" "} ov) </Text> </Text> </View> ))} </View> {match.winnerName && (<View className="flex-row items-center mb-2"> <Trophy size={16} color="#16A34A" /> <Text className="text-sm font-semibold text-green-600 ml-2"> {match.winnerName} won </Text> {match.winMargin && (<Text className="text-sm text-gray-500 ml-1"> {match.winMargin} </Text> )} </View> )} {match.manOfTheMatchName && (<View className="flex-row items-center"> <Award size={14} color="#F59E0B" /> <Text className="text-sm font-medium text-amber-500 ml-2"> MOTM: {match.manOfTheMatchName} </Text> </View> )} </TouchableOpacity> );const renderMatchDetailsModal = () => {if (!selectedMatch) return null;return (<Modalvisible={showMatchDetails}transparentanimationType="slide"onRequestClose={closeMatchDetails}> <View className="flex-1 bg-black/70 justify-center items-center p-4"> <View className="bg-white rounded-2xl w-full max-w-lg max-h-[90%]"> {/* Header */} <View className="flex-row justify-between items-center p-6 border-b border-gray-200"> <Text className="text-xl font-bold text-gray-900"> Match Details </Text> <TouchableOpacityonPress={closeMatchDetails}className="p-2 bg-gray-100 rounded-lg"> <X size={24} color="#6B7280" /> </TouchableOpacity> </View> <ScrollViewclassName="flex-1"showsVerticalScrollIndicator={false}contentContainerStyle="p-6"> {/* Match Info */} <View className="bg-gray-50 rounded-xl p-5 mb-6 items-center"> <Text className="text-xl font-bold text-gray-900 text-center"> {selectedMatch.team1Name} vs {selectedMatch.team2Name} </Text> <Text className="text-base text-gray-500 text-center mt-2"> {formatDate(selectedMatch.date)} • {selectedMatch.totalOvers}{" "} overs </Text> {selectedMatch.winnerName && (<View className="flex-row items-center bg-green-50 rounded-lg px-4 py-2 mt-4"> <Trophy size={20} color="#16A34A" /> <Text className="text-base font-semibold text-green-600 ml-2"> {selectedMatch.winnerName} won {selectedMatch.winMargin} </Text> </View> )} </View> {/* Innings Scores */} <View className="flex-row gap-3 mb-6"> {selectedMatch.innings.map((innings, index) => (<Viewkey={index}className="flex-1 bg-white rounded-xl border border-gray-200 p-4"> <View className="flex-row justify-between items-center mb-2"> <Text className="text-sm font-semibold text-gray-500 flex-1"> {innings.battingTeam} Innings </Text> <Text className="text-lg font-bold text-green-600"> {innings.totalRuns}/{innings.totalWickets} </Text> </View> <Text className="text-sm text-gray-400"> {Math.floor(innings.totalBalls / 6)}. {innings.totalBalls % 6} overs </Text> </View> ))} </View> {/* Batting Stats */} {selectedMatch.innings.map((innings, inningsIndex) => (<View key={`batting-${inningsIndex}`} className="mb-6"> <Text className="text-lg font-bold text-gray-900 mb-3"> {innings.battingTeam} Batting </Text> <View className="bg-white rounded-xl border border-gray-200 overflow-hidden"> <View className="flex-row bg-gray-50 py-3 px-4 border-b border-gray-200"> <Text className="flex-[2] text-sm font-semibold text-gray-500"> Player </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Runs </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Balls </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> 4s/6s </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> SR </Text> </View> {innings.battingStats?.map((stat, index) => (<Viewkey={index}className="flex-row py-3 px-4 border-b border-gray-100 last:border-b-0"> <TextclassName="flex-[2] text-sm text-gray-900"numberOfLines={1}> {stat.playerName} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.runs} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.balls} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.fours}/{stat.sixes} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.strikeRate.toFixed(1)} </Text> </View> ))} </View> </View> ))} {/* Bowling Stats */} {selectedMatch.innings.map((innings, inningsIndex) => (<View key={`bowling-${inningsIndex}`} className="mb-6"> <Text className="text-lg font-bold text-gray-900 mb-3"> {innings.bowlingTeam} Bowling </Text> <View className="bg-white rounded-xl border border-gray-200 overflow-hidden"> <View className="flex-row bg-gray-50 py-3 px-4 border-b border-gray-200"> <Text className="flex-[2] text-sm font-semibold text-gray-500"> Player </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Overs </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Runs </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Wkts </Text> <Text className="flex-1 text-sm font-semibold text-gray-500 text-center"> Econ </Text> </View> {innings.bowlingStats?.map((stat, index) => (<Viewkey={index}className="flex-row py-3 px-4 border-b border-gray-100 last:border-b-0"> <TextclassName="flex-[2] text-sm text-gray-900"numberOfLines={1}> {stat.playerName} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.overs} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.runs} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.wickets} </Text> <Text className="flex-1 text-sm text-gray-900 text-center"> {stat.economy.toFixed(1)} </Text> </View> ))} </View> </View> ))} {/* Man of the Match */} {selectedMatch.manOfTheMatchName && (<View className="bg-amber-50 rounded-xl p-5"> <View className="flex-row justify-center items-center mb-3"> <Award size={20} color="#F59E0B" /> <Text className="text-lg font-bold text-amber-800 ml-2"> Man of the Match </Text> </View> <Text className="text-xl font-bold text-amber-800 text-center"> {selectedMatch.manOfTheMatchName} </Text> </View> )} </ScrollView> </View> </View> </Modal> ); };if (isLoading) {return (<SafeAreaView className="flex-1 bg-gray-50"> <View className="bg-green-600 px-5 py-4"> <Text className="text-2xl font-bold text-white text-center"> Match History </Text> <Text className="text-sm text-green-100 text-center mt-1"> Loading matches... </Text> </View> <View className="flex-1 justify-center items-center p-10"> <Clock size={48} color="#D1D5DB" /> <Text className="text-base text-gray-500 mt-4"> Loading match history... </Text> </View> </SafeAreaView> ); }if (error) {return (<SafeAreaView className="flex-1 bg-gray-50"> <View className="bg-green-600 px-5 py-4"> <Text className="text-2xl font-bold text-white text-center"> Match History </Text> <Text className="text-sm text-green-100 text-center mt-1"> Error loading matches </Text> </View> <View className="flex-1 justify-center items-center p-10"> <Text className="text-lg font-semibold text-red-500 mb-2"> Failed to load match history </Text> <Text className="text-base text-gray-500 text-center"> Please check your connection and try again </Text> </View> </SafeAreaView> ); }const matches = matchesData?.matches || [];return (<SafeAreaView className="flex-1 bg-gray-50"> <View className="bg-green-600 px-5 py-4"> <Text className="text-2xl font-bold text-white text-center"> Match History </Text> <Text className="text-sm text-green-100 text-center mt-1"> {matches.length} match{matches.length !== 1 ? "es" : ""} found </Text> </View> {matches.length === 0 ? (<View className="flex-1 justify-center items-center p-10"> <Trophy size={80} color="#D1D5DB" /> <Text className="text-xl font-bold text-gray-700 mt-4"> No Matches Yet </Text> <Text className="text-base text-gray-500 text-center mt-2"> Complete matches will appear here in your history </Text> </View> ) : (<ScrollViewclassName="flex-1 p-4"showsVerticalScrollIndicator={false}contentContainerStyle="pb-6"> {matches.map(renderMatchCard)} </ScrollView> )} {renderMatchDetailsModal()} </SafeAreaView> );}this is match-setup under tabs"use client";import { useState } from "react";import {View,Text,ScrollView,TouchableOpacity,Alert,Modal,TextInput,} from "react-native";import { SafeAreaView } from "react-native-safe-area-context";import {Calendar,Users,Trophy,ArrowRight,Plus,X,Clock,} from "lucide-react-native";import { router } from "expo-router";import { useCricketStore } from "../../store/cricketStore";export default function MatchSetupTab() {const { teams, players, addPlayer, updatePlayer, deletePlayer, startMatch } =useCricketStore();const [selectedDate, setSelectedDate] = useState(new Date());const [team1Id, setTeam1Id] = useState("");const [team2Id, setTeam2Id] = useState("");const [tossWinnerId, setTossWinnerId] = useState("");const [tossDecision, setTossDecision] = useState("bat");const [totalOvers, setTotalOvers] = useState(20);const [showPlayerModal, setShowPlayerModal] = useState(false);const [currentTeamForPlayer, setCurrentTeamForPlayer] = useState("");const [playerName, setPlayerName] = useState("");const [playerRole, setPlayerRole] = useState("batsman");const [editingPlayer, setEditingPlayer] = useState(null);const oversOptions = [8, 10, 12, 15, 20, 25, 30, 50];const formatDate = (date) => {const dateObj = date instanceof Date ? date : new Date(date);return dateObj.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", }); };const handleEditPlayer = (player) => {setCurrentTeamForPlayer(player.teamId);setPlayerName(player.name);setPlayerRole(player.role);setEditingPlayer(player);setShowPlayerModal(true); };const handleUpdatePlayer = () => {if (!editingPlayer || !playerName.trim()) {Alert.alert("Error", "Please enter player name");return; }const updatedPlayer = {...editingPlayer, name: playerName.trim(), role: playerRole, };updatePlayer(updatedPlayer);setPlayerName("");setPlayerRole("batsman");setEditingPlayer(null);setShowPlayerModal(false); };const handleDeletePlayer = (playerId) => {Alert.alert("Delete Player","Are you sure you want to delete this player?", [ { text: "Cancel", style: "cancel" }, { text: "Delete", style: "destructive",onPress: () => deletePlayer(playerId), }, ] ); };const handleAddPlayer = () => {if (editingPlayer) {handleUpdatePlayer();return; }if (!playerName.trim()) {Alert.alert("Error", "Please enter player name");return; }const newPlayer = { id: Date.now().toString(), name: playerName.trim(), role: playerRole, teamId: currentTeamForPlayer, };addPlayer(newPlayer);setPlayerName("");setPlayerRole("batsman");setShowPlayerModal(false); };const openPlayerModal = (teamId) => {setCurrentTeamForPlayer(teamId);setEditingPlayer(null);setPlayerName("");setPlayerRole("batsman");setShowPlayerModal(true); };const getTeamPlayers = (teamId) => {return players.filter((player) => player.teamId === teamId); };const canStartMatch = () => {if (!team1Id || !team2Id || !tossWinnerId) return false;const team1Players = getTeamPlayers(team1Id);const team2Players = getTeamPlayers(team2Id);return team1Players.length >= 7 && team2Players.length >= 7; };const handleStartMatch = () => {if (!team1Id || !team2Id || !tossWinnerId) {Alert.alert("Error", "Please select both teams and toss winner");return; }if (team1Id === team2Id) {Alert.alert("Error", "Please select different teams");return; }const team1Players = getTeamPlayers(team1Id);const team2Players = getTeamPlayers(team2Id);if (team1Players.length < 7 || team2Players.length < 7) {Alert.alert("Error", "Each team must have at least 7 players");return; }const battingTeamId =tossDecision === "bat"? tossWinnerId: tossWinnerId === team1Id? team2Id: team1Id;const bowlingTeamId = battingTeamId === team1Id ? team2Id : team1Id;const newMatch = { id: Date.now().toString(), date: selectedDate,team1Id,team2Id,battingTeamId,bowlingTeamId,tossWinnerId,tossDecision,totalOvers, status: "live", currentInnings: 1, innings: [ { id: Date.now().toString() + "_1", teamId: battingTeamId, totalRuns: 0, totalWickets: 0, totalOvers: 0, totalBalls: 0, balls: [], currentBatsmanIds: [], currentBowlerId: "", currentNonStrikerId: "", }, ], createdAt: new Date(), };startMatch(newMatch);router.push("/(tabs)/live-scoring"); };const getTeamName = (teamId) => {return teams.find((team) => team.id === teamId)?.name || "Select Team"; };return (<SafeAreaView className="flex-1 bg-gray-50"> <View className="bg-green-600 p-5 pt-2.5"> <Text className="text-2xl font-bold text-white text-center"> New Match Setup </Text> <Text className="text-sm text-green-100 text-center mt-1"> Configure your cricket match </Text> </View> <ScrollView className="flex-1 p-5" showsVerticalScrollIndicator={false}> {/* Date Selection */} <View className="mb-6"> <View className="flex-row items-center mb-3"> <Calendar size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-900 ml-2"> Match Date </Text> </View> <View className="bg-white rounded-xl p-4 shadow-md shadow-black/5"> <Text className="text-base text-gray-900 text-center"> {formatDate(selectedDate)} </Text> </View> </View> {/* Overs Selection */} <View className="mb-6"> <View className="flex-row items-center mb-3"> <Clock size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-900 ml-2"> Match Format </Text> </View> <View className="bg-white rounded-xl p-4 shadow-md shadow-black/5"> <Text className="text-sm font-semibold text-gray-600 mb-2"> Select Overs </Text> <ScrollViewhorizontalshowsHorizontalScrollIndicator={false}className="flex-row"> {oversOptions.map((overs) => (<TouchableOpacitykey={overs}className={`bg-gray-100 rounded-lg py-2 px-4 mr-2 min-w-[50px] items-center ${totalOvers === overs ? "bg-green-600" : ""}`}onPress={() => setTotalOvers(overs)}> <TextclassName={`text-sm font-semibold ${totalOvers === overs ? "text-white" : "text-gray-900"}`}> {overs} </Text> </TouchableOpacity> ))} </ScrollView> </View> </View> {/* Team Selection */} <View className="mb-6"> <View className="flex-row items-center mb-3"> <Users size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-900 ml-2"> Select Teams </Text> </View> <View className="bg-white rounded-xl p-5 shadow-md shadow-black/5"> <View className="mb-4"> <Text className="text-sm font-semibold text-gray-600 mb-2"> Team 1 </Text> <ScrollViewhorizontalshowsHorizontalScrollIndicator={false}className="flex-row"> {teams.map((team) => (<TouchableOpacitykey={team.id}className={`bg-gray-100 rounded-lg py-2 px-4 mr-2 min-w-[60px] items-center ${team1Id === team.id ? "bg-green-600" : ""}`}onPress={() => setTeam1Id(team.id)}disabled={team.id === team2Id}> <TextclassName={`text-sm font-semibold ${team1Id === team.id ? "text-white" : "text-gray-900"} ${team.id === team2Id ? "text-gray-400" : ""}`}> {team.shortName} </Text> </TouchableOpacity> ))} </ScrollView> </View> <View className="items-center mb-4"> <Text className="text-lg font-bold text-orange-500">VS</Text> </View> <View className="mb-4"> <Text className="text-sm font-semibold text-gray-600 mb-2"> Team 2 </Text> <ScrollViewhorizontalshowsHorizontalScrollIndicator={false}className="flex-row"> {teams.map((team) => (<TouchableOpacitykey={team.id}className={`bg-gray-100 rounded-lg py-2 px-4 mr-2 min-w-[60px] items-center ${team2Id === team.id ? "bg-green-600" : ""}`}onPress={() => setTeam2Id(team.id)}disabled={team.id === team1Id}> <TextclassName={`text-sm font-semibold ${team2Id === team.id ? "text-white" : "text-gray-900"} ${team.id === team1Id ? "text-gray-400" : ""}`}> {team.shortName} </Text> </TouchableOpacity> ))} </ScrollView> </View> </View> </View> {/* Players Section */} {team1Id && team2Id && (<View className="mb-6"> <View className="flex-row items-center mb-3"> <Users size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-900 ml-2"> Team Players </Text> </View> <View className="bg-white rounded-xl p-4 shadow-md shadow-black/5"> {/* Team 1 Players */} <View className="mb-4"> <View className="flex-row justify-between items-center mb-2"> <Text className="text-base font-semibold text-gray-900"> {getTeamName(team1Id)} ({getTeamPlayers(team1Id).length}) </Text> <TouchableOpacityclassName="bg-green-50 rounded px-1.5 py-1.5"onPress={() => openPlayerModal(team1Id)}> <Plus size={16} color="#16A34A" /> </TouchableOpacity> </View> <ScrollView className="max-h-30" nestedScrollEnabled> {getTeamPlayers(team1Id).length > 0 ? (getTeamPlayers(team1Id).map((player) => (<Viewkey={player.id}className="flex-row justify-between items-center bg-white rounded-md p-2 mb-1 border border-gray-200"> <View className="flex-1"> <Text className="text-sm text-gray-700"> {player.name} ({player.role}) </Text> </View> <View className="flex-row gap-2"> <TouchableOpacityclassName="bg-blue-500 rounded px-2 py-1"onPress={() => handleEditPlayer(player)}> <Text className="text-xs text-white font-semibold"> Edit </Text> </TouchableOpacity> <TouchableOpacityclassName="bg-red-500 rounded px-2 py-1"onPress={() => handleDeletePlayer(player.id)}> <Text className="text-xs text-white font-semibold"> Delete </Text> </TouchableOpacity> </View> </View> )) ) : (<Text className="text-sm text-gray-400 italic text-center p-4"> No players added yet </Text> )} </ScrollView> </View> {/* Team 2 Players */} <View className="mb-4"> <View className="flex-row justify-between items-center mb-2"> <Text className="text-base font-semibold text-gray-900"> {getTeamName(team2Id)} ({getTeamPlayers(team2Id).length}) </Text> <TouchableOpacityclassName="bg-green-50 rounded px-1.5 py-1.5"onPress={() => openPlayerModal(team2Id)}> <Plus size={16} color="#16A34A" /> </TouchableOpacity> </View> <ScrollView className="max-h-30" nestedScrollEnabled> {getTeamPlayers(team2Id).length > 0 ? (getTeamPlayers(team2Id).map((player) => (<Viewkey={player.id}className="flex-row justify-between items-center bg-white rounded-md p-2 mb-1 border border-gray-200"> <View className="flex-1"> <Text className="text-sm text-gray-700"> {player.name} ({player.role}) </Text> </View> <View className="flex-row gap-2"> <TouchableOpacityclassName="bg-blue-500 rounded px-2 py-1"onPress={() => handleEditPlayer(player)}> <Text className="text-xs text-white font-semibold"> Edit </Text> </TouchableOpacity> <TouchableOpacityclassName="bg-red-500 rounded px-2 py-1"onPress={() => handleDeletePlayer(player.id)}> <Text className="text-xs text-white font-semibold"> Delete </Text> </TouchableOpacity> </View> </View> )) ) : (<Text className="text-sm text-gray-400 italic text-center p-4"> No players added yet </Text> )} </ScrollView> </View> </View> </View> )} {/* Toss */} {team1Id && team2Id && (<View className="mb-6"> <View className="flex-row items-center mb-3"> <Trophy size={20} color="#16A34A" /> <Text className="text-lg font-semibold text-gray-900 ml-2"> Toss </Text> </View> <View className="bg-white rounded-xl p-5 shadow-md shadow-black/5"> <Text className="text-sm font-semibold text-gray-600 mb-3"> Toss Winner </Text> <View className="flex-row gap-3 mb-4"> <TouchableOpacityclassName={`flex-1 bg-gray-100 rounded-lg p-3 items-center ${tossWinnerId === team1Id ? "bg-green-600" : ""}`}onPress={() => setTossWinnerId(team1Id)}> <TextclassName={`text-sm font-semibold ${tossWinnerId === team1Id ? "text-white" : "text-gray-900"}`}> {getTeamName(team1Id)} </Text> </TouchableOpacity> <TouchableOpacityclassName={`flex-1 bg-gray-100 rounded-lg p-3 items-center ${tossWinnerId === team2Id ? "bg-green-600" : ""}`}onPress={() => setTossWinnerId(team2Id)}> <TextclassName={`text-sm font-semibold ${tossWinnerId === team2Id ? "text-white" : "text-gray-900"}`}> {getTeamName(team2Id)} </Text> </TouchableOpacity> </View> {tossWinnerId && (<View className="mt-4"> <Text className="text-sm font-semibold text-gray-600 mb-3"> Choose to </Text> <View className="flex-row gap-3 mb-4"> <TouchableOpacityclassName={`flex-1 bg-gray-100 rounded-lg p-3 items-center ${tossDecision === "bat" ? "bg-orange-500" : ""}`}onPress={() => setTossDecision("bat")}> <TextclassName={`text-sm font-semibold ${tossDecision === "bat"? "text-white": "text-gray-900"}`}> Bat First </Text> </TouchableOpacity> <TouchableOpacityclassName={`flex-1 bg-gray-100 rounded-lg p-3 items-center ${tossDecision === "bowl" ? "bg-orange-500" : ""}`}onPress={() => setTossDecision("bowl")}> <TextclassName={`text-sm font-semibold ${tossDecision === "bowl"? "text-white": "text-gray-900"}`}> Bowl First </Text> </TouchableOpacity> </View> </View> )} </View> </View> )} {/* Start Match Button */} {canStartMatch() && (<TouchableOpacityclassName="bg-green-600 rounded-xl p-4 flex-row items-center justify-center mt-5 shadow-md shadow-black/5"onPress={handleStartMatch}> <Text className="text-lg font-bold text-white mr-2"> Start Match </Text> <ArrowRight size={20} color="#FFFFFF" /> </TouchableOpacity> )} {team1Id && team2Id && !canStartMatch() && (<View className="bg-yellow-100 rounded-lg p-3 mt-4"> <Text className="text-sm text-yellow-800 text-center"> Both teams need at least 7 players to start the match </Text> </View> )} </ScrollView> {/* Add Player Modal */} <Modalvisible={showPlayerModal}transparentanimationType="slide"onRequestClose={() => setShowPlayerModal(false)}> <View className="flex-1 bg-black/50 justify-center items-center p-5"> <View className="bg-white rounded-xl p-5 w-full max-w-lg"> <View className="flex-row justify-between items-center mb-5"> <Text className="text-lg font-semibold text-gray-900"> {editingPlayer ? "Edit Player" : "Add Player"} </Text> <TouchableOpacityclassName="p-1"onPress={() => {setShowPlayerModal(false);setEditingPlayer(null);setPlayerName("");setPlayerRole("batsman"); }}> <X size={20} color="#6B7280" /> </TouchableOpacity> </View> <TextInputclassName="border border-gray-300 rounded-lg p-3 text-base text-gray-900 mb-4"placeholder="Player Name"value={playerName}onChangeText={setPlayerName}autoFocus/> <Text className="text-sm font-semibold text-gray-600 mb-2"> Player Role </Text> <View className="flex-row flex-wrap gap-2 mb-5"> {["batsman", "bowler", "all-rounder", "wicketkeeper"].map( (role) => (<TouchableOpacitykey={role}className={`bg-gray-100 rounded-md py-1.5 px-3 ${playerRole === role ? "bg-green-600" : ""}`}onPress={() => setPlayerRole(role)}> <TextclassName={`text-xs font-semibold ${playerRole === role ? "text-white" : "text-gray-900"}`}> {role.charAt(0).toUpperCase() + role.slice(1)} </Text> </TouchableOpacity> ) )} </View> <TouchableOpacityclassName="bg-green-600 rounded-lg p-3 items-center"onPress={handleAddPlayer}> <Text className="text-base font-semibold text-white"> {editingPlayer ? "Update Player" : "Add Player"} </Text> </TouchableOpacity> </View> </View> </Modal> </SafeAreaView> );}and this is index under tabs"use client"import { useState } from "react"import { View, Text, ScrollView, TouchableOpacity, TextInput, Alert, Modal } from "react-native"import { SafeAreaView } from "react-native-safe-area-context"import { Plus, Users, Edit3, Trash2, X } from "lucide-react-native"import { useCricketStore } from "../../store/cricketStore"export default function TeamsTab() {const { teams, players, addTeam, updateTeam, deleteTeam, addPlayer, updatePlayer, deletePlayer } = useCricketStore()const [showAddTeam, setShowAddTeam] = useState(false)const [showEditTeam, setShowEditTeam] = useState(false)const [showEditPlayer, setShowEditPlayer] = useState(false)const [expandedTeams, setExpandedTeams] = useState(new Set())const [teamName, setTeamName] = useState("")const [shortName, setShortName] = useState("")const [editingTeam, setEditingTeam] = useState(null)const [editingPlayer, setEditingPlayer] = useState(null)const [playerName, setPlayerName] = useState("")const [playerRole, setPlayerRole] = useState("batsman")const handleAddTeam = () => {if (!teamName.trim() || !shortName.trim()) {Alert.alert("Error", "Please enter both team name and short name")return }const newTeam = { id: Date.now().toString(), name: teamName.trim(), shortName: shortName.trim().toUpperCase(), color: "#16A34A", createdAt: new Date(), }addTeam(newTeam)setTeamName("")setShortName("")setShowAddTeam(false) }const handleEditTeam = (team) => {setEditingTeam(team)setTeamName(team.name)setShortName(team.shortName)setShowEditTeam(true) }const handleUpdateTeam = () => {if (!editingTeam || !teamName.trim() || !shortName.trim()) {Alert.alert("Error", "Please enter both team name and short name")return }const updatedTeam = {...editingTeam, name: teamName.trim(), shortName: shortName.trim().toUpperCase(), }updateTeam(updatedTeam)setTeamName("")setShortName("")setEditingTeam(null)setShowEditTeam(false) }const handleDeleteTeam = (teamId) => {Alert.alert("Delete Team","Are you sure you want to delete this team? This will also delete all players in this team.", [ { text: "Cancel", style: "cancel" }, { text: "Delete", style: "destructive", onPress: () => deleteTeam(teamId) }, ], ) }const handleEditPlayer = (player) => {setEditingPlayer(player)setPlayerName(player.name)setPlayerRole(player.role)setShowEditPlayer(true) }const handleUpdatePlayer = () => {if (!editingPlayer || !playerName.trim()) {Alert.alert("Error", "Please enter player name")return }const updatedPlayer = {...editingPlayer, name: playerName.trim(), role: playerRole, }updatePlayer(updatedPlayer)setPlayerName("")setPlayerRole("batsman")setEditingPlayer(null)setShowEditPlayer(false) }const handleDeletePlayer = (playerId) => {Alert.alert("Delete Player", "Are you sure you want to delete this player?", [ { text: "Cancel", style: "cancel" }, { text: "Delete", style: "destructive", onPress: () => deletePlayer(playerId) }, ]) }const getTeamPlayers = (teamId) => {return players.filter((player) => player.teamId === teamId) }const toggleTeamExpansion = (teamId) => {const newExpanded = new Set(expandedTeams)if (newExpanded.has(teamId)) {newExpanded.delete(teamId) } else {newExpanded.add(teamId) }setExpandedTeams(newExpanded) }return (<SafeAreaView className="flex-1 bg-gray-50"> <View className="bg-primary-500 px-5 py-4 pt-2.5"> <Text className="text-3xl font-bold text-white text-center">CricScore Pro</Text> <Text className="text-base text-primary-100 text-center mt-1">Manage Teams & Players</Text> </View> <ScrollView className="flex-1 p-5" showsVerticalScrollIndicator={false}> {teams.map((team) => {const teamPlayers = getTeamPlayers(team.id)return (<View key={team.id} className="mb-5"> <View className="bg-white rounded-3xl p-4 mb-2 shadow-lg"> <TouchableOpacity className="flex-row items-center flex-1" onPress={() => toggleTeamExpansion(team.id)}> <View className="w-3 h-3 rounded-full mr-3" style={{ backgroundColor: team.color }} /> <View className="flex-1"> <Text className="text-base font-semibold text-gray-800">{team.name}</Text> <Text className="text-sm text-gray-500 mt-0.5"> {team.shortName} ({teamPlayers.length} players) </Text> </View> <View className="flex-row gap-2"> <TouchableOpacity className="p-2 rounded-lg bg-gray-100" onPress={() => handleEditTeam(team)}> <Edit3 size={16} color="#6B7280" /> </TouchableOpacity> <TouchableOpacity className="p-2 rounded-lg bg-gray-100" onPress={() => handleDeleteTeam(team.id)}> <Trash2 size={16} color="#EF4444" /> </TouchableOpacity> </View> </TouchableOpacity> </View> {/* Players List */} {expandedTeams.has(team.id) && (<View className="bg-slate-50 rounded-2xl p-3 ml-6"> <Text className="text-sm font-semibold text-gray-600 mb-2">Players</Text> {teamPlayers.map((player) => (<Viewkey={player.id}className="flex-row justify-between items-center py-1.5 px-2 bg-white rounded-lg mb-1"> <View className="flex-1"> <Text className="text-sm text-gray-800">{player.name}</Text> <Text className="text-xs text-gray-500">({player.role})</Text> </View> <View className="flex-row gap-1"> <TouchableOpacityclassName="p-2 rounded-lg bg-gray-100"onPress={() => handleEditPlayer(player)}> <Edit3 size={14} color="#6B7280" /> </TouchableOpacity> <TouchableOpacityclassName="p-2 rounded-lg bg-gray-100"onPress={() => handleDeletePlayer(player.id)}> <Trash2 size={14} color="#EF4444" /> </TouchableOpacity> </View> </View> ))} </View> )} </View> ) })} {showAddTeam ? (<View className="bg-white rounded-3xl p-5 mb-5 shadow-lg"> <Text className="text-lg font-semibold text-gray-800 mb-4">Add New Team</Text> <TextInputclassName="border border-gray-300 rounded-2xl p-3 text-base text-gray-800 mb-3 bg-white"placeholder="Team Name"value={teamName}onChangeText={setTeamName}placeholderTextColor="#9CA3AF"/> <TextInputclassName="border border-gray-300 rounded-2xl p-3 text-base text-gray-800 mb-3 bg-white"placeholder="Short Name (e.g., MI, CSK)"value={shortName}onChangeText={setShortName}placeholderTextColor="#9CA3AF"maxLength={3}/> <View className="flex-row gap-3 mt-2"> <TouchableOpacityclassName="flex-1 p-3 rounded-2xl bg-gray-100 items-center"onPress={() => setShowAddTeam(false)}> <Text className="text-base font-semibold text-gray-600">Cancel</Text> </TouchableOpacity> <TouchableOpacity className="flex-1 p-3 rounded-2xl bg-primary-500 items-center" onPress={handleAddTeam}> <Text className="text-base font-semibold text-white">Add Team</Text> </TouchableOpacity> </View> </View> ) : (<TouchableOpacityclassName="bg-white rounded-3xl p-5 items-center mb-5 border-2 border-gray-200 border-dashed"onPress={() => setShowAddTeam(true)}> <Plus size={24} color="#16A34A" /> <Text className="text-base font-semibold text-primary-500 mt-2">Add New Team</Text> </TouchableOpacity> )} <View className="mt-5"> <View className="bg-white rounded-3xl p-5 items-center shadow-lg"> <Users size={24} color="#16A34A" /> <Text className="text-3xl font-bold text-primary-500 mt-2">{teams.length}</Text> <Text className="text-sm text-gray-500 mt-1">Total Teams</Text> </View> </View> </ScrollView> {/* Edit Team Modal */} <Modal visible={showEditTeam} transparent animationType="slide" onRequestClose={() => setShowEditTeam(false)}> <View className="flex-1 bg-black/50 justify-center items-center p-5"> <View className="bg-white rounded-3xl p-5 w-full max-w-sm"> <View className="flex-row justify-between items-center mb-5"> <Text className="text-lg font-semibold text-gray-800">Edit Team</Text> <TouchableOpacity onPress={() => setShowEditTeam(false)}> <X size={20} color="#6B7280" /> </TouchableOpacity> </View> <TextInputclassName="border border-gray-300 rounded-2xl p-3 text-base text-gray-800 mb-3 bg-white"placeholder="Team Name"value={teamName}onChangeText={setTeamName}placeholderTextColor="#9CA3AF"/> <TextInputclassName="border border-gray-300 rounded-2xl p-3 text-base text-gray-800 mb-3 bg-white"placeholder="Short Name"value={shortName}onChangeText={setShortName}placeholderTextColor="#9CA3AF"maxLength={3}/> <TouchableOpacity className="bg-primary-500 rounded-2xl p-3 items-center" onPress={handleUpdateTeam}> <Text className="text-base font-semibold text-white">Update Team</Text> </TouchableOpacity> </View> </View> </Modal> {/* Edit Player Modal */} <Modal visible={showEditPlayer} transparent animationType="slide" onRequestClose={() => setShowEditPlayer(false)}> <View className="flex-1 bg-black/50 justify-center items-center p-5"> <View className="bg-white rounded-3xl p-5 w-full max-w-sm"> <View className="flex-row justify-between items-center mb-5"> <Text className="text-lg font-semibold text-gray-800">Edit Player</Text> <TouchableOpacity onPress={() => setShowEditPlayer(false)}> <X size={20} color="#6B7280" /> </TouchableOpacity> </View> <TextInputclassName="border border-gray-300 rounded-2xl p-3 text-base text-gray-800 mb-4 bg-white"placeholder="Player Name"value={playerName}onChangeText={setPlayerName}placeholderTextColor="#9CA3AF"/> <Text className="text-sm font-semibold text-gray-600 mb-2">Player Role</Text> <View className="flex-row flex-wrap gap-2 mb-4"> {["batsman", "bowler", "all-rounder", "wicketkeeper"].map((role) => (<TouchableOpacitykey={role}className={`px-3 py-1.5 rounded-lg ${playerRole === role ? "bg-primary-500" : "bg-gray-100"}`}onPress={() => setPlayerRole(role)}> <Text className={`text-xs font-semibold ${playerRole === role ? "text-white" : "text-gray-800"}`}> {role.charAt(0).toUpperCase() + role.slice(1)} </Text> </TouchableOpacity> ))} </View> <TouchableOpacity className="bg-primary-500 rounded-2xl p-3 items-center mt-2" onPress={handleUpdatePlayer}> <Text className="text-base font-semibold text-white">Update Player</Text> </TouchableOpacity> </View> </View> </Modal> </SafeAreaView> )}so, after match setup when click on start match and after match completed those two times app crash and showing that error,also instead of react navigation will be better to use expo router and taps, also the top status bar not showing properly and bottom status bar goes under the touch screen icon, button not rounded and the team selection button not toggle properly. if user select team 1 a then team 2 will automatically other except a also can be toggle from by select team 2 first also runs and these button looks smaller and not rounded so update the design on the live score 4 and 6 button text not showingfixed all the issue, update design with more beautiful layout and optimized the code.Also selected data must be persist till submited on db, and current match history should shown from the persist but all previous completed will fetch from api and show list way in history tab, and when click on there will open the match details modal with all details,
Loading...
check these screenshot for all design to fix.in all tabs bottom navigation goes under the device touch icon, also header not showing properly.when click on add new team, input submit/add button goese under the keyboardin new match tab, header not showing, selected button not showing properly, selected overs, teams, and the start match button, also add/edit player modal button not showing and those role not showing properly specially the selected one, toss winner selected team and choice selected option also not showing and in live score tab 4 and six still not showingthis is the current tailiwindcss config/** @type {import('tailwindcss').Config} /module.exports = { darkMode: ["class"], content: ["./app/**/.{js,jsx,ts,tsx}","./components/**/.{js,jsx,ts,tsx}",".{js,ts,jsx,tsx,mdx}", ], presets: [require("nativewind/preset")], theme: {}, plugins: ["tailwindcss-animate"],};and this is the my previous project tab layout, which was working fine for design and not goes under the touch screen iconimport { router, Tabs } from "expo-router";import { useContext, useEffect, useMemo } from "react";import { View, Text } from "react-native";import { Feather } from "@expo/vector-icons";import { useSafeAreaInsets } from "react-native-safe-area-context";// Internal importsimport useCartStore from "@store/cartStore";import { useAuth } from "@context/AuthContext";import { SidebarContext } from "@context/SidebarContext";import useUtilsFunction from "@hooks/useUtilsFunction";import CustomTabButton from "@components/common/button/CustomTabButton";const TabLayout = () => {const insets = useSafeAreaInsets();//contextconst { staff, loading } = useAuth();const { selectedTable } = useContext(SidebarContext);//custom hooksconst { pos_view, isTableEnabled } = useUtilsFunction();// Zustand storeconst { cartItem } = useCartStore();const isTableSelected = useMemo(() => {return (Object?.keys(selectedTable || {})?.length > 0 &&pos_view &&isTableEnabled ); }, [selectedTable, pos_view, isTableEnabled]);const totalItems = useMemo(() => {return cartItem?.reduce((pre, cur) => pre + cur.quantity, 0) || 0; }, [cartItem]);// console.log("selectedTable", selectedTable);// console.log("staff", staff);useEffect(() => {if (!staff && !loading) {router.replace("/login"); } }, [staff, loading]);return (<> <TabsscreenOptions={{ headerShown: false, tabBarInactiveTintColor: "#2a2828
", tabBarActiveTintColor: "#2563eb
", tabBarStyle: { backgroundColor: "#fff", borderTopWidth: 1, borderTopColor: "#ddd", height: 60 + insets.bottom, paddingBottom: insets.bottom, elevation: 0, shadowOpacity: 0, shadowColor: "transparent", }, tabBarLabelStyle: { fontSize: 14, fontWeight: "600", }, tabBarBadgeStyle: { top: -5, right: -10, },tabBarButton: (props) => <CustomTabButton {...props} />, }}> <Tabs.Screenname="pos"options={{// tabBarLabel: "Cart", tabBarLabel: "New",tabBarIcon: ({ color, size }) => (<Viewstyle={{ justifyContent: "center", alignItems: "center", height: size, }}> <Feather name="layers" size={size} color={color} /> </View> ), }}listeners={{tabPress: (e) => {e.preventDefault(); // Stop tab navigationif (isTableEnabled && !isTableSelected) {router.push("table-lists"); } else {router.push("pos"); } }, }}/> <Tabs.Screenname="table"options={{ tabBarLabel: "",tabBarButton: () =>isTableSelected ? (<ViewclassName="my-auto"style={{ backgroundColor: "#e5e7eb
", paddingHorizontal: 4, marginHorizontal: 4, paddingVertical: 10, borderRadius: 8, maxWidth: "100%", flexDirection: "row", textAlign: "center", alignItems: "center", justifyContent: "center", }}> <Textstyle={{ fontSize: 12, fontWeight: "600", color: "#e60075
", textAlign: "center", }}numberOfLines={1}ellipsizeMode="tail"> {selectedTable?.name || selectedTable?.table_name} </Text> </View> ) : null, }}/> <Tabs.Screenname="cart"options={{// tabBarLabel: "Cart", tabBarLabel: "Order",tabBarIcon: ({ color, size }) => (<Viewstyle={{ justifyContent: "center", alignItems: "center", height: size, }}> <Feather name="shopping-bag" size={size} color={color} /> </View> ), tabBarBadge: totalItems > 0 ? totalItems : undefined, }}listeners={{tabPress: (e) => {e.preventDefault(); // Stop tab navigation// if (router?.canDismiss()) {// router?.dismissAll();// }router.push("cart"); }, }}/> </Tabs> </> );};export default TabLayout;also the team select toggle, bowl or bat toggle over toggle not working faster, bit slow as well