// 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 && (

Twitter

)}
{player.social?.facebook && (

Facebook

)}
{player.social?.instagram && (

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 => (

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)}
/>
)}

); };
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}

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

Live Score Leagues News Players Teams Fantasy Videos

{/* Removed fetchData prop */} ) } 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 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 A similar topic I found on stackoverflow 2
So basically when the user clicks on an image, I am displaying the details of the image as a modal/dialog box. But after the dialog box is closed, the screen scroll freezes. Things work on the screen, but I cant scroll down and access the other elements. Any idea how i can debug.

I feel its because somehow the modal is disabling my scroll bar.

Below is my dialog box code

import React from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { Fragment } from 'react'
import {XIcon} from '@heroicons/react/solid'
import {useRecoilState} from 'recoil'
import {openState} from '../../../atoms/modalAtom'

const product = {
name: "Women's Basic Tee",
price: '$32',
rating: 3.9,
reviewCount: 512,
href: '#',
imageSrc: 'https://tailwindui.com/img/ecommerce-images/product-page-01-featured-product-shot.jpg',
imageAlt: "Back of women's Basic Tee in black.",
colors: [
{ name: 'Black', bgColor: 'bg-gray-900', selectedColor: 'ring-gray-900' },
{ name: 'Heather Grey', bgColor: 'bg-gray-400', selectedColor: 'ring-gray-400' },
],
sizes: [
{ name: 'XXS', inStock: true },
{ name: 'XS', inStock: true },
{ name: 'S', inStock: true },
{ name: 'M', inStock: true },
{ name: 'L', inStock: true },
{ name: 'XL', inStock: true },
{ name: 'XXL', inStock: false },
],
}

export function DesignQuickView ({design}) {
const [open, setOpen] = useRecoilState(openState)

return (
<Transition.Root show={open} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={() => setOpen(false)}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"

</Transition.Child>


<div className="fixed z-10 inset-0 overflow-y-auto">
  <div className="flex items-stretch md:items-center justify-center min-h-full text-center md:px-2 lg:px-4">
    {/* This element is to trick the browser into centering the modal contents. */}
    <span className="hidden md:inline-block md:align-middle md:h-screen" aria-hidden="true">
      &#8203;
    </span>
    <Transition.Child
      as={Fragment}
      enter="ease-out duration-300"
      enterFrom="opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
      enterTo="opacity-100 translate-y-0 md:scale-100"
      leave="ease-in duration-200"
      leaveFrom="opacity-100 translate-y-0 md:scale-100"
      leaveTo="opacity-0 translate-y-4 md:translate-y-0 md:scale-95"
    >
      <Dialog.Panel className="flex text-base text-left transform transition w-full md:max-w-2xl md:px-4 md:my-8 lg:max-w-4xl">
        <div className="w-full relative flex items-center bg-white px-4 pt-14 pb-8 overflow-hidden shadow-2xl sm:px-6 sm:pt-8 md:p-6 lg:p-8">
          <button
            type="button"
            className="absolute top-4 right-4 text-gray-400 hover:text-gray-500 sm:top-8 sm:right-6 md:top-6 md:right-6 lg:top-8 lg:right-8"
            onClick={() => setOpen(false)}
          >
            <span className="sr-only">Close</span>
            <XIcon className="h-6 w-6" aria-hidden="true" />
          </button>

          <div className="w-full grid grid-cols-1 gap-y-8 gap-x-6 items-start sm:grid-cols-12 lg:items-center lg:gap-x-8">
            <div className="aspect-w-2 aspect-h-3 rounded-lg bg-gray-100 overflow-hidden sm:col-span-4 lg:col-span-5">
              <img src={design.url} alt={design.name} className="object-center object-cover" />
            </div>
            <div className="sm:col-span-8 lg:col-span-7">
              <h2 className="text-xl font-medium text-gray-900 sm:pr-12">Hoodie</h2>

              <section aria-labelledby="information-heading" className="mt-1">
                <h3 id="information-heading" className="sr-only">
                  Product information
                </h3>

                <p className="font-medium text-gray-900">{product.price}</p>

              
              </section>

              <section aria-labelledby="options-heading" className="mt-8">
                <h3 id="options-heading" className="sr-only">
                  Product options
                </h3>

                <form>
                  {/* Color picker */}
                  <div>
                    <h4 className="text-sm font-medium text-gray-900">Color</h4>

                    {/* <RadioGroup value={selectedColor} onChange={setSelectedColor} className="mt-2">
                      <RadioGroup.Label className="sr-only">Choose a color</RadioGroup.Label>
                      <div className="flex items-center space-x-3">
                        {product.colors.map((color) => (
                          <RadioGroup.Option
                            key={color.name}
                            value={color}
                            className={({ active, checked }) =>
                              classNames(
                                color.selectedColor,
                                active && checked ? 'ring ring-offset-1' : '',
                                !active && checked ? 'ring-2' : '',
                                '-m-0.5 relative p-0.5 rounded-full flex items-center justify-center cursor-pointer focus:outline-none'
                              )
                            }
                          >
                            <RadioGroup.Label as="span" className="sr-only">
                              {color.name}
                            </RadioGroup.Label>
                            <span
                              aria-hidden="true"
                              className={classNames(
                                color.bgColor,
                                'h-8 w-8 border border-black border-opacity-10 rounded-full'
                              )}
                            />
                          </RadioGroup.Option>
                        ))}
                      </div>
                    </RadioGroup> */}
                  </div>

                  {/* Size picker */}
                  <div className="mt-8">
                    <div className="flex items-center justify-between">
                      <h4 className="text-sm font-medium text-gray-900">Size</h4>
                      <a href="#" className="text-sm font-medium text-indigo-600 hover:text-indigo-500">
                        Size guide
                      </a>
                    </div>

                    {/* <RadioGroup value={selectedSize} onChange={setSelectedSize} className="mt-2">
                      <RadioGroup.Label className="sr-only">Choose a size</RadioGroup.Label>
                      <div className="grid grid-cols-7 gap-2">
                        {product.sizes.map((size) => (
                          <RadioGroup.Option
                            key={size.name}
                            value={size}
                            className={({ active, checked }) =>
                              classNames(
                                size.inStock
                                  ? 'cursor-pointer focus:outline-none'
                                  : 'opacity-25 cursor-not-allowed',
                                active ? 'ring-2 ring-offset-2 ring-indigo-500' : '',
                                checked
                                  ? 'bg-indigo-600 border-transparent text-white hover:bg-indigo-700'
                                  : 'bg-white border-gray-200 text-gray-900 hover:bg-gray-50',
                                'border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium uppercase sm:flex-1'
                              )
                            }
                            disabled={!size.inStock}
                          >
                            <RadioGroup.Label as="span">{size.name}</RadioGroup.Label>
                          </RadioGroup.Option>
                        ))}
                      </div>
                    </RadioGroup> */}
                  </div>

                </form>
              </section>
            </div>
          </div>
        </div>
      </Dialog.Panel>
    </Transition.Child>
  </div>
</div>
) }
export default DesignQuickView

Here is how i am calling the modal/ dialog box

const Design = ({design}) => {

const [open, setOpen] = useRecoilState(openState)

return(

//Wrapping the image in a card



<img className= "inline-block h-14 w-14 rounded-md "
src={design.url}
alt="Custom design"
onClick={()=>setOpen(true)}

            />

        </div>
        <DesignQuickView design= {design}/>

</div>
    )
}

export default Design
I think its the scrollbar. Any leads on how i can debug?

javascriptreactjsnext.jstailwind-csstailwind-ui
Share
Edit
Follow
asked Jul 10, 2022 at 21:40
rohit's user avatar
rohit
17922 silver badges1515 bronze badges
Add a comment
1 Answer
Sorted by:

Highest score (default)
2

I had the same issue where after closing the modal, scrolling stopped working on the main page.

Problem: I was rendering a list where each item had a button to open up the modal, and I had put the modal inside that list.

const [isOpen, setIsOpen] = useState(false);
const data = [
// My data was an array of objects,
// where each object contained position data
]

const closeModal = () => {
setIsOpen(false);
};

const openModal = () => {
setIsOpen(true);
};

{data.map((position) => ( Open Modal // <--------- Problem! ))}
Solution: Move the modal out of the list and create a state variable that gets updated in the openModal and closeModal functions:
const [selectedPosition, setSelectedPosition] = useState(null);
const [isOpen, setIsOpen] = useState(false);

const data = [
// My data was an array of objects,
// where each object contained position data
]

const closeModal = () => {
setSelectedPosition(null);
setIsOpen(false);
};

const openModal = (position) => {
setSelectedPosition(position);
setIsOpen(true);
};

{data.map((position) => ( openModal(position)}>Open Modal ))} // <-------- Solved!
I'm using shadcn UI with next js don't change any config