Tailwind: Displaying a modal inside another modal messes up UI

102 views Asked by At

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"
        >
          &#8203;
        </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}
        />
      )}

enter image description here

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:
enter image description here

Any idea what's going on?

0

There are 0 answers