I have this modal:
import React from "react";
type ModalProps = {
title: string;
body: React.ReactNode;
onClose: () => void;
};
const Modal: React.FC<ModalProps> = ({ title, body, onClose }) => {
return (
<div className="modal fixed z-10 inset-0 overflow-y-auto">
<div className="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0 ">
<div
className="fixed inset-0 transition-opacity"
onClick={onClose}
aria-hidden="true"
>
<div className="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
​
</span>
<div
className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4 bg-gray-900">
<h3
className="modal-title text-lg font-medium text-gray-900 text-center text-white"
id="modal-headline"
>
{title}
</h3>
<div className="modal-body mt-2">{body}</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
onClick={onClose}
type="button"
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
Close
</button>
</div>
</div>
</div>
</div>
);
};
export default Modal;
I have Players
component that can display a matches modal:
{selectedPlayer && (
<Modal
title="Matches won by this player"
body={
<Matches matches={gamesWon} selectedPlayerId={selectedPlayer.id} />
}
onClose={handleCloseModal}
/>
)}
This is the Matches component:
import React from "react";
import { Match } from "../../types";
import MatchComponent from "./Match";
type MatchesProps = {
matches: Match[];
selectedPlayerId: string;
};
const Matches: React.FC<MatchesProps> = ({ matches, selectedPlayerId }) => {
return (
<div className="matches-list">
{matches.map((match, i) => (
<MatchComponent
matchNumber={i + 1}
key={match.id}
match={match}
selectedPlayerId={selectedPlayerId}
/>
))}
</div>
);
};
export default Matches;
It displays a list of Match
components. When I click on opponent in the Match component, I want to display another modal that shows the opponent details. So this is the Match component:
import React, { useState } from "react";
import { Match, Player } from "../../types";
import {
getTimeFromString,
getDateFromString,
} from "../../helpers/dateHelpers";
import { useSelector } from "react-redux";
import Opponent from "./Opponent";
import Modal from "../common/Modal";
type MatchProps = {
match: Match;
matchNumber: number;
selectedPlayerId: string;
};
const MatchComponent: React.FC<MatchProps> = ({
match,
matchNumber,
selectedPlayerId,
}) => {
const [showOpponentModal, setShowOpponentModal] = useState(false);
const { players } = useSelector((state: any) => state.players);
const opponent = match.players.find(
(player) => player.id !== selectedPlayerId
);
const opponentId = opponent?.id;
const opponentData = players.find(
(player: Player) => player.id == opponentId
);
console.log(" ~ file: Match.tsx:33 ~ players:", players);
console.log(" ~ file: Match.tsx:22 ~ opponent:", opponent);
console.log(" ~ file: Match.tsx:33 ~ opponentData:", opponentData);
const handleOpponentClick = (opponentId: string) => {
setShowOpponentModal(true);
};
const handleCloseModal = () => {
setShowOpponentModal(false);
};
return (
<div className="bg-yellow-100 p-4 rounded shadow-md mb-4 bg-blue-100 hover:transform hover:scale-105 hover:transition-transform hover:duration-300">
<h4 className="text-indigo-600 text-lg font-semibold mb-2">
Match {matchNumber}: {getDateFromString(match.startTime)}
</h4>
<div className="text-gray-700 text-base">
<span className="font-bold text-teal-600">Start Time:</span>{" "}
{getTimeFromString(match.startTime)}
</div>
<div className="text-gray-700 text-base">
<span className="font-bold text-teal-600">End Time:</span>{" "}
{getTimeFromString(match.endTime)}
</div>
<h5 className="text-indigo-600 text-lg font-semibold mt-4 mb-2">
Opponent:
</h5>
<ul className="list-disc ml-6">
{opponent ? (
<li
key={opponent.id}
className="text-gray-600"
onClick={() => handleOpponentClick(opponent.id)}
>
{opponent.firstname} {opponent.lastname}
</li>
) : (
<li className="text-gray-600">No opponent found</li>
)}
</ul>
{showOpponentModal && (
<Modal
title="Matches won by this player"
body={
<Opponent
opponent={opponentData}
onClose={() => setShowOpponentModal(false)}
/>
}
onClose={handleCloseModal}
/>
)}
</div>
);
};
export default MatchComponent;
It works but the Matches modal and the Opponent modal overlap and each time one of them appears and disappears quickly when I hover with the pointer on the modals but, when the pointer is outside, it works fine:
Any idea what's going on?