Files
tm_panel/src/components/ui/modal.tsx
T
AmirReza Jamali 1d1027fab4 fix: add null checks for document and firebase messaging to prevent SSR errors
Added defensive programming by adding null checks for document object before accessing its properties and methods across multiple components (MultiSelect, ConfirmationModal, Dropdown, Modal). Also implemented lazy initialization for Firebase messaging to prevent SSR-related errors and ensure messaging is only initialized on the client side. These changes improve server-side rendering compatibility and prevent potential runtime errors.
2025-11-15 12:22:30 +03:30

94 lines
2.7 KiB
TypeScript

import { CrossIcon } from "@/assets/icons";
import { useIsMutating } from "@tanstack/react-query";
import { ReactNode, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import IsVisible from "./IsVisible";
interface ModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm?: () => void;
children: ReactNode;
confirmText?: string;
cancelText?: string;
showButtons?: boolean;
classNames?: string;
}
const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
children,
onConfirm,
confirmText = "confirm",
cancelText = "close",
showButtons = true,
classNames,
}) => {
const [mounted, setMounted] = useState(false);
const isMutating = useIsMutating();
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (isOpen) {
if (document) document.body.style.overflow = "hidden";
} else {
if (document) document.body.style.overflow = "unset";
}
return () => {
if (document) document.body.style.overflow = "unset";
};
}, [isOpen]);
if (!mounted || !isOpen) return null;
const modalContent = (
<div
className="fixed inset-0 z-999999 flex items-center justify-center bg-dark/50 dark:bg-black/50"
onClick={onClose}
>
<div
className={`max-h-[90vh] max-w-[90vw] overflow-auto rounded-lg bg-white p-5 shadow-4 dark:bg-dark-2 ${classNames}`}
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
className="float-right mb-2.5 cursor-pointer border-none bg-transparent p-0 text-2xl text-dark-5 hover:text-primary dark:text-gray-5 dark:hover:text-primary"
>
<CrossIcon />
</button>
<div className="clear-both">{children}</div>
<div className="flex gap-5">
<IsVisible condition={showButtons}>
<button
type="submit"
className="mt-6 flex w-fit justify-center rounded-lg bg-primary p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
onClick={onConfirm}
>
{isMutating ? (
<div className="h-5 w-5 animate-spin rounded-full border-b-2 border-gray-1"></div>
) : (
<span>{confirmText}</span>
)}
</button>
<button
type="button"
className="mt-6 flex w-fit justify-center rounded-lg bg-error p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
onClick={onClose}
>
{cancelText}
</button>
</IsVisible>
</div>
</div>
</div>
);
return createPortal(modalContent, document.body);
};
export default Modal;