// component/PlayerModal.tsx
'use client';

import { useEffect, useState } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogClose } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { getPlayerDetails, getPlayerMatches } from '../utils/api';
import { Player, Match } from '../types';
import { useRouter } from 'next/navigation';
import { FaTwitter, FaFacebook, FaInstagram } from 'react-icons/fa';

interface PlayerModalProps {
playerId: string;
isOpen: boolean;
onClose: () => void;
}

const PlayerModal: React.FC = ({ playerId, isOpen, onClose }) => {
const [player, setPlayer] = useState<Player | null>(null);
const [matches, setMatches] = useState<Match[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const router = useRouter();

useEffect(() => {
if (isOpen) {
setLoading(true);
setError('');
const fetchPlayerData = async () => {
try {
const fetchedPlayer = await getPlayerDetails(playerId);
setPlayer(fetchedPlayer);
const fetchedMatches = await getPlayerMatches(playerId, 5);
setMatches(fetchedMatches);
} catch (err: any) {
setError(err);
} finally {
setLoading(false);
}
};
fetchPlayerData();
}
}, [isOpen, playerId]);

const handleViewMatches = () => {
onClose(); // Close the modal
router.push(/players/${playerId}/matches);
};

if (!isOpen) return null;

return (




{player?.name}


{loading ? (
Loading...


) : error ? (
{error}


) : player ? (


{player.photo_url ? (
{player.name}
) : (
{player.name.charAt(0)}
)}


Position: {player.position || 'N/A'}


Nationality: {player.nationality || 'N/A'}


Team: {player.team || 'N/A'}


League: {player.league || 'N/A'}


Birthday: {player.birthday || 'N/A'}


Height: {player.height || 'N/A'}


Weight: {player.weight || 'N/A'}


Jersey Number: {player.jerseyNumber || 'N/A'}


Description: {player.description || 'No description available.'}



{player.social?.twitter && (
<a href={https://twitter.com/${player.social.twitter}} target="_blank" rel="noopener noreferrer">

Twitter


)}
{player.social?.facebook && (
<a href={https://facebook.com/${player.social.facebook}} target="_blank" rel="noopener noreferrer">

Facebook


)}
{player.social?.instagram && (
<a href={https://instagram.com/${player.social.instagram}} target="_blank" rel="noopener noreferrer">

Instagram


)}


View Recent Matches



) : (
Player not found.


)}


);
};
export default PlayerModal;

// component/PlayerSearch.tsx
'use client';

import { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import PlayerModal from './PlayerModal';
import { Player } from '../types';
import { searchPlayers } from '../utils/api';
import { toast } from 'react-toastify';

const PlayerSearch: React.FC = () => {
const [searchTerm, setSearchTerm] = useState('');
const [players, setPlayers] = useState<Player[]>([]);
const [loading, setLoading] = useState(false);
const [selectedPlayerId, setSelectedPlayerId] = useState<string | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);

const handleSearch = async () => {
if (!searchTerm.trim()) {
toast.error("Please enter a search term.");
setPlayers([]);
return;
}


setLoading(true);
setPlayers([]);

try {
  const data = await searchPlayers(searchTerm);
  setPlayers(data);
  if (data.length === 0) {
    toast.info("No players found. Try a different search.");
  }
} catch (error: any) {
  toast.error(error);
} finally {
  setLoading(false);
}
};

const handlePlayerClick = (playerId: string) => {
setSelectedPlayerId(playerId);
setIsModalOpen(true);
};

const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
handleSearch();
}
};

return (




Player Search



<Input
type="text"
placeholder="Search players..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onKeyPress={handleKeyPress}
/>

{loading ? 'Searching...' : 'Search'}



{loading ? (
Searching...


) : (
players.map(player => (
<div
key={player.player_id}
className="flex items-center p-4 bg-white rounded shadow hover:bg-gray-100 cursor-pointer"
onClick={() => handlePlayerClick(player.player_id)}
>

{player.photo_url ? (
{player.name}
) : (

{player.name.charAt(0)}

)}


{player.name}

{player.position} - {player.team}




))
)}



  {/* Player Modal */}
  {selectedPlayerId && (
    <PlayerModal 
      playerId={selectedPlayerId} 
      isOpen={isModalOpen} 
      onClose={() => setIsModalOpen(false)} 
    />
  )}
</div>
);
};

export default PlayerSearch;

// component/Navbar.tsx
'use client';

import Link from 'next/link';
import { Button } from "@/components/ui/button";

const Navbar: React.FC = () => {
return (





FootballBuzz


{/* Add more navigation links if needed */}


);
};
export default Navbar;

// app/players/[id]/matches/page.tsx
'use client';

import { useEffect, useState } from 'react';
import { useRouter, useParams } from 'next/navigation';
import { getPlayerMatches, getPlayerDetails } from '../../../../utils/api';
import { Player, Match } from '../../../../types';
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import Navbar from '../../../../component/Navbar';
import Link from 'next/link';
import { toast } from 'react-toastify';
import { Avatar, AvatarFallback } from "@/components/ui/avatar";

const PlayerMatchesPage: React.FC = () => {
const router = useRouter();
const params = useParams();
const { id } = params;
const [player, setPlayer] = useState<Player | null>(null);
const [matches, setMatches] = useState<Match[]>([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
if (!id) {
router.push('/');
return;
}


const fetchData = async () => {
  try {
    const fetchedPlayer = await getPlayerDetails(id);
    setPlayer(fetchedPlayer);
    const fetchedMatches = await getPlayerMatches(id, 5);
    setMatches(fetchedMatches);
  } catch (error: any) {
    toast.error(error);
  } finally {
    setLoading(false);
  }
};

fetchData();
}, [id, router]);

if (loading) return

Loading matches...

;
if (!player) return
Player not found.

;
return (
<>





Recent Matches of {player.name}

<Link href={/players/${id}}>
Back to Player Details


Home




{matches.length === 0 ? (
No recent matches found.


) : (

{matches.map(match => (


{match.homeTeam} vs {match.awayTeam}


{match.date} at {match.time}



Score: {match.homeScore !== null ? ${match.homeScore} - ${match.awayScore} : 'N/A'}


Status: {match.status}


League: {match.league}


Season: {match.season}




))}

)}




</>
);
};
export default PlayerMatchesPage;

// app/players/[id]/page.tsx
'use client';

import { useEffect, useState } from 'react';
import { useRouter, useParams } from 'next/navigation';
import PlayerModal from '../../../component/PlayerModal';
import Navbar from '../../../component/Navbar';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const PlayerPage: React.FC = () => {
const router = useRouter();
const params = useParams();
const { id } = params;
const [isModalOpen, setIsModalOpen] = useState(true);

useEffect(() => {
if (!id) {
router.push('/'); // Redirect to home if no player ID is found
}
}, [id, router]);

const handleClose = () => {
setIsModalOpen(false);
router.push('/'); // Redirect to home upon closing the modal
};

return (
<>



</>
);
};

export default PlayerPage;

// types/index.ts

export interface Player {
player_id: string;
name: string;
position: string;
nationality: string;
team: string;
league: string;
photo_url?: string;
description?: string;
birthday?: string;
height?: string;
weight?: string;
jerseyNumber?: string;
social?: {
twitter?: string;
facebook?: string;
instagram?: string;
};
}

export interface Match {
event_id: string;
league: string;
season: string;
date: string;
time: string;
homeTeam: string;
awayTeam: string;
homeScore: number | null;
awayScore: number | null;
status: string;
player_id: string;
fetchedAt: Date;
}

// utils/api.ts

import axios from 'axios';
import { Player, Match } from '../types';

// Ensure to set NEXT_PUBLIC_API_BASE_URL in your .env.local
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:5000/api';

/**

Search players by name.
@param query - Player name query.
@returns Promise resolving to an array of Player objects.
*/
export const searchPlayers = async (query: string): Promise<Player[]> => {
try {
const response = await axios.get(${API_BASE_URL}/searchPlayers, {
params: { q: query },
});
return response.data.players;
} catch (error: any) {
console.error('Search Players Error:', error);
throw error.response?.data?.error || 'Error searching players';
}
};
/**

Get detailed information about a specific player by ID.
@param playerId - Unique identifier of the player.
@returns Promise resolving to a Player object.
*/
export const getPlayerDetails = async (playerId: string): Promise => {
try {
const response = await axios.get(${API_BASE_URL}/playerDetails/${playerId});
return response.data.response;
} catch (error: any) {
console.error('Get Player Details Error:', error);
throw error.response?.data?.error || 'Error fetching player details';
}
};
/**

Get recent matches for a specific player.
@param playerId - Unique identifier of the player.
@param limit - Number of recent matches to retrieve.
@returns Promise resolving to an array of Match objects.
*/
export const getPlayerMatches = async (playerId: string, limit: number = 5): Promise<Match[]> => {
try {
const response = await axios.get(${API_BASE_URL}/playerMatches/${playerId}, {
params: { limit },
});
return response.data.matches;
} catch (error: any) {
console.error('Get Player Matches Error:', error);
throw error.response?.data?.error || 'Error fetching player matches';
}
};
// routes/playerRoutes.js

const express = require("express");
const router = express.Router();
const playerController = require("../controllers/playerSearchController");

// Search Players
router.get("/searchPlayers", playerController.searchPlayers);

// Get Player Details
router.get("/playerDetails/:id", playerController.getPlayerDetails);

// Get Player Matches
router.get("/playerMatches/:id", playerController.getPlayerMatches);

module.exports = router;

// controllers/playerSearchController.js

// controllers/playerSearchController.js

const axios = require("axios");
const Player = require("../models/Player");
const Match = require("../models/Match");

// Base URL for the V1 API provided by TheSportsDB
const baseURL = "https://www.thesportsdb.com/api/v1/json/3";

// Helper function to make API requests
const makeApiRequest = async (endpoint, params = {}) => {
try {
const response = await axios.get(${baseURL}/${endpoint}, { params });
console.log(API Response for ${endpoint} with params ${JSON.stringify(params)}:, response.data);
return response.data;
} catch (error) {
if (error.response) {
console.error(
API Error: ${error.response.status} - ${JSON.stringify( error.response.data )}
);
throw new Error(
API Error: ${error.response.data.error || "Unknown error"}
);
} else if (error.request) {
console.error("No response received from API");
throw new Error("No response received from API");
} else {
console.error("Error setting up the request:", error.message);
throw new Error("Error setting up the request");
}
}
};

/**

Search for players by name directly using the new V1 API.
Returns up to 5 matching players.
*/
exports.searchPlayers = async (req, res) => {
const query = req.query.q;
if (!query) {
return res.status(400).json({ error: "Search query 'q' is required" });
}

try {
// Search in the local database first
const localPlayers = await Player.find({
name: { $regex: query, $options: "i" },
}).limit(5);


if (localPlayers.length > 0) {
  return res.json({ count: localPlayers.length, players: localPlayers });
}

// If not found locally, fetch from API
const playersResponse = await makeApiRequest("searchplayers.php", {
  p: query,
});

// Validate response structure
if (
  !playersResponse ||
  !playersResponse.player ||
  !Array.isArray(playersResponse.player)
) {
  return res
    .status(404)
    .json({ error: "No players found matching the query" });
}

// Limit to 5 players
const limitedPlayers = playersResponse.player.slice(0, 3);

// Enrich player data with necessary fields
const enrichedPlayers = limitedPlayers.map((player) => ({
  player_id: player.idPlayer,
  name: player.strPlayer,
  position: player.strPosition || "N/A",
  nationality: player.strNationality || "N/A",
  team: player.strTeam || "N/A",
  league: player.strLeague || "N/A",
  photo_url: player.strThumb || null,
  description: player.strDescriptionEN || "No description available.",
  birthday: player.dateBorn || "N/A",
  height: player.strHeight || "N/A",
  weight: player.strWeight || "N/A",
  jerseyNumber: player.strNumber || "N/A",
  social: {
    twitter: player.strTwitter || null,
    facebook: player.strFacebook || null,
    instagram: player.strInstagram || null,
  },
}));

// Save fetched players to the local database
await Player.insertMany(
  enrichedPlayers,
  { ordered: false } // Continue on duplicate errors
).catch((err) => {
  if (err.code === 11000) {
    console.warn("Duplicate player entries detected.");
  } else {
    console.error("Error inserting players into DB:", err.message);
  }
});

res.json({ count: enrichedPlayers.length, players: enrichedPlayers });
} catch (error) {
console.error("Error in searchPlayers:", error.message);
res.status(500).json({ error: error.message });
}
};

/**

Get detailed information about a specific player by ID using the new V1 API.
*/
exports.getPlayerDetails = async (req, res) => {
const playerId = req.params.id;
if (!playerId) {
return res.status(400).json({ error: "Player ID is required" });
}

try {
// Check local DB first
const localPlayer = await Player.findOne({ player_id: playerId });


if (localPlayer) {
  console.log(`Player ID "${playerId}" found in local DB.`);
  return res.json({ status: "success", response: localPlayer });
}

console.log(
  `Player ID "${playerId}" not found in local DB. Fetching from API.`
);

// If not found locally, fetch from API
const playerDetailsResponse = await makeApiRequest("lookupplayer.php", {
  id: playerId,
});

// Validate response structure
if (
  !playerDetailsResponse ||
  playerDetailsResponse.players === null ||
  !Array.isArray(playerDetailsResponse.players) ||
  playerDetailsResponse.players.length === 0
) {
  console.warn(`API returned no data for Player ID "${playerId}".`);
  return res.status(404).json({ error: "Player not found" });
}

const player = playerDetailsResponse.players[0];

// Structure the player details
const detailedPlayer = {
  player_id: player.idPlayer,
  name: player.strPlayer,
  position: player.strPosition || "N/A",
  nationality: player.strNationality || "N/A",
  team: player.strTeam || "N/A",
  league: player.strLeague || "N/A",
  photo_url: player.strThumb || null,
  description: player.strDescriptionEN || "No description available.",
  birthday: player.dateBorn || "N/A",
  height: player.strHeight || "N/A",
  weight: player.strWeight || "N/A",
  jerseyNumber: player.strNumber || "N/A",
  social: {
    twitter: player.strTwitter || null,
    facebook: player.strFacebook || null,
    instagram: player.strInstagram || null,
  },
};

console.log(`Fetched player details for Player ID "${playerId}" from API.`);

// Save to local DB
try {
  await Player.create(detailedPlayer);
  console.log(`Player ID "${playerId}" saved to local DB.`);
} catch (err) {
  if (err.code === 11000) {
    console.warn(`Player ID "${playerId}" already exists in the database.`);
  } else {
    console.error("Error inserting player into DB:", err.message);
  }
}

res.json({ status: "success", response: detailedPlayer });
} catch (error) {
console.error("Error in getPlayerDetails:", error.message);
if (
error.message.includes("404") ||
error.message.toLowerCase().includes("not found")
) {
res.status(404).json({ error: "Player not found" });
} else {
res.status(500).json({ error: error.message });
}
}
};

/**

Get recent matches/events for a specific player using the new V1 API.
This example assumes that you have stored matches in your local DB.
*/
exports.getPlayerMatches = async (req, res) => {
const playerId = req.params.id;
const limit = parseInt(req.query.limit) || 5;
if (!playerId) {
return res.status(400).json({ error: "Player ID is required" });
}

try {
// Check if the player exists in the database
const player = await Player.findOne({ player_id: playerId });
if (!player) {
console.log(
Player ID "${playerId}" not found in local DB. Fetching player details to proceed.
);
// Attempt to fetch player details from API
const playerDetailsResponse = await makeApiRequest("lookupplayer.php", {
id: playerId,
});


  // Validate response structure
  if (
    !playerDetailsResponse ||
    playerDetailsResponse.players === null ||
    !Array.isArray(playerDetailsResponse.players) ||
    playerDetailsResponse.players.length === 0
  ) {
    console.warn(`API returned no data for Player ID "${playerId}".`);
    return res.status(404).json({ error: "Player not found" });
  }

  const playerData = playerDetailsResponse.players[0];

  // Structure the player details
  const detailedPlayer = {
    player_id: playerData.idPlayer,
    name: playerData.strPlayer,
    position: playerData.strPosition || "N/A",
    nationality: playerData.strNationality || "N/A",
    team: playerData.strTeam || "N/A",
    league: playerData.strLeague || "N/A",
    photo_url: playerData.strThumb || null,
    description: playerData.strDescriptionEN || "No description available.",
    birthday: playerData.dateBorn || "N/A",
    height: playerData.strHeight || "N/A",
    weight: playerData.strWeight || "N/A",
    jerseyNumber: playerData.strNumber || "N/A",
    social: {
      twitter: playerData.strTwitter || null,
      facebook: playerData.strFacebook || null,
      instagram: playerData.strInstagram || null,
    },
  };

  // Save to local DB
  try {
    await Player.create(detailedPlayer);
    console.log(`Player ID "${playerId}" saved to local DB.`);
  } catch (err) {
    if (err.code === 11000) {
      console.warn(
        `Player ID "${playerId}" already exists in the database.`
      );
    } else {
      console.error("Error inserting player into DB:", err.message);
    }
  }
} else {
  console.log(`Player ID "${playerId}" found in local DB.`);
}

// Now that the player exists in the database, fetch matches
// Check local DB for matches
const localMatches = await Match.find({ player_id: playerId })
  .sort({ date: -1 })
  .limit(limit);

if (localMatches.length >= limit) {
  console.log(
    `Found ${localMatches.length} matches in local DB for Player ID "${playerId}".`
  );
  return res.json({
    count: localMatches.length,
    matches: localMatches,
  });
}

console.log(
  `Found only ${localMatches.length} matches in local DB for Player ID "${playerId}". Fetching additional matches from API.`
);

// Fetch player details to get the team ID
const playerDetailsResponse = await makeApiRequest("lookupplayer.php", {
  id: playerId,
});

if (
  !playerDetailsResponse ||
  playerDetailsResponse.players === null ||
  !Array.isArray(playerDetailsResponse.players) ||
  playerDetailsResponse.players.length === 0
) {
  throw new Error("Player not found");
}

const playerData = playerDetailsResponse.players[0];
const teamId = playerData.idTeam;

if (!teamId) {
  throw new Error("Team ID not available for this player");
}

// Fetch recent events for the team
const eventsResponse = await makeApiRequest("eventslast.php", {
  id: teamId,
});

if (
  !eventsResponse ||
  !eventsResponse.results ||
  !Array.isArray(eventsResponse.results)
) {
  throw new Error("No events found for the player's team");
}

// Structure the match details
const matches = eventsResponse.results
  .slice(0, limit - localMatches.length)
  .map((event) => ({
    event_id: event.idEvent,
    league: event.strLeague,
    season: event.strSeason,
    date: event.dateEvent,
    time: event.strTime,
    homeTeam: event.strHomeTeam,
    awayTeam: event.strAwayTeam,
    homeScore: event.intHomeScore,
    awayScore: event.intAwayScore,
    status: event.strStatus,
    player_id: playerId,
    fetchedAt: new Date(),
  }));

console.log(
  `Fetched ${matches.length} new matches from API for Player ID "${playerId}".`
);

// Save new matches to local DB
await Match.insertMany(
  matches,
  { ordered: false } // Continue on duplicate errors
).catch((err) => {
  if (err.code === 11000) {
    console.warn("Duplicate match entries detected.");
  } else {
    console.error("Error inserting matches into DB:", err.message);
  }
});

// Combine local and newly fetched matches
const combinedMatches = [...localMatches, ...matches].slice(0, limit);

console.log(
  `Returning ${combinedMatches.length} matches for Player ID "${playerId}".`
);

res.json({ count: combinedMatches.length, matches: combinedMatches });
} catch (error) {
console.error("Error in getPlayerMatches:", error.message);
res.status(500).json({ error: error.message });
}
};

Now what is going on is that I am not able to search player

'use client'

import { useState } from 'react'
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import LiveScore from './LiveScore'
import LeagueSelector from './LeagueSelector'
import NewsArticles from './NewsArticles'
import PlayerSearch from './PlayerSearch'
import TeamHistory from './TeamHistory'
import FantasySports from './FantasySports'
import VideoContent from './VideoContent'

// Mock API function
const fetchData = async (endpoint) => {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 500))
// Return mock data based on endpoint
switch (endpoint) {
case 'liveScore':
return { homeTeam: "Team A", awayTeam: "Team B", homeScore: 2, awayScore: 1 }
case 'leagues':
return ['Premier League', 'La Liga', 'Bundesliga', 'Serie A', 'Ligue 1', 'Champions League', 'Europa League']
case 'news':
return [
{ id: 1, title: "Breaking: Star Player Injured", content: "Team A's star player out for 3 weeks..." },
{ id: 2, title: "Transfer Rumors: Who's Moving Where?", content: "Latest transfer gossip from around the league..." },
]
case 'players':
return [
{ id: 1, name: "Lionel Messi", team: "Inter Miami", position: "Forward" },
{ id: 2, name: "Cristiano Ronaldo", team: "Al Nassr", position: "Forward" },
]
case 'teams':
return [
{ id: 1, name: "Manchester United", league: "Premier League", history: "Founded in 1878, 20 league titles..." },
{ id: 2, name: "Real Madrid", league: "La Liga", history: "Founded in 1902, 34 La Liga titles..." },
]
default:
return []
}
}

export default function FootballDashboard() {
const [activeTab, setActiveTab] = useState('liveScore')

return (


FootballBuzz

  <Tabs value={activeTab} onValueChange={setActiveTab} className="mb-6">
    <TabsList>
      <TabsTrigger value="liveScore">Live Score</TabsTrigger>
      <TabsTrigger value="leagues">Leagues</TabsTrigger>
      <TabsTrigger value="news">News</TabsTrigger>
      <TabsTrigger value="players">Players</TabsTrigger>
      <TabsTrigger value="teams">Teams</TabsTrigger>
      <TabsTrigger value="fantasy">Fantasy</TabsTrigger>
      <TabsTrigger value="videos">Videos</TabsTrigger>
    </TabsList>

    <TabsContent value="liveScore">
      <LiveScore fetchData={fetchData} />
    </TabsContent>
    <TabsContent value="leagues">
      <LeagueSelector /> {/* Removed fetchData prop */}
    </TabsContent>
    <TabsContent value="news">
      <NewsArticles fetchData={fetchData} />
    </TabsContent>
    <TabsContent value="players">
      <PlayerSearch />
    </TabsContent>
    <TabsContent value="teams">
      <TeamHistory fetchData={fetchData} />
    </TabsContent>
    <TabsContent value="fantasy">
      <FantasySports />
    </TabsContent>
    <TabsContent value="videos">
      <VideoContent />
    </TabsContent>
  </Tabs>
</div>
)
}
This is FootballDashboard.tsx

Now Problem is that on clicking photo+name it is showing me player but when screen opens there's no option of scrolling , home, IG, last 5 matches and many things which backend has fetched so I think problem is with frontend because backend is working fine photo is half cut one details screen 
Can you please solve it make it scrollable and make it beutifull