Files
tm_panel/src/components/ui/modal.tsx
T
AmirReza Jamali 5b73389d64 feat(admins): add filter functionality to admins list
This commit introduces filtering capabilities to the administrators table, allowing users to refine the list based on specific criteria.

A new `ListHeader` component has been implemented, which now contains the "Create Admin" button and a new "Filter" button. Clicking the filter button opens a modal containing the `AdminListFilters` form. The state for managing the filter modal's visibility is handled within the `useAdminsPresenter` hook. A new `FilterIcon` has also been added to support this feature.
2025-10-12 15:20:52 +03:30

94 lines
2.6 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) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "unset";
}
return () => {
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;