144 lines
3.5 KiB
TypeScript
144 lines
3.5 KiB
TypeScript
import { createContext, useCallback, useContext, useState } from "react";
|
|
|
|
interface ModalState {
|
|
contentType: string;
|
|
entityId?: string;
|
|
entityLabel?: string;
|
|
closeOnClickOutside?: boolean;
|
|
}
|
|
|
|
interface Props {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
interface ModalContextType {
|
|
isOpen: boolean;
|
|
openModal: (
|
|
contentType: string,
|
|
entityId?: string,
|
|
entityLabel?: string,
|
|
closeOnClickOutside?: boolean,
|
|
) => void;
|
|
closeModal: () => void;
|
|
closeModals: (count: number) => void;
|
|
clearAllModals: () => void;
|
|
modalContentType: string;
|
|
entityId: string;
|
|
entityLabel: string;
|
|
closeOnClickOutside: boolean;
|
|
modalStates: Record<string, any>;
|
|
setModalState: (modalType: string, state: any) => void;
|
|
getModalState: (modalType: string) => any;
|
|
clearModalState: (modalType: string) => void;
|
|
clearAllModalStates: () => void;
|
|
}
|
|
|
|
const ModalContext = createContext<ModalContextType | undefined>(undefined);
|
|
|
|
export const ModalProvider: React.FC<Props> = ({ children }) => {
|
|
const [modalStack, setModalStack] = useState<ModalState[]>([]);
|
|
const [modalStates, setModalStates] = useState<Record<string, any>>({});
|
|
|
|
const isOpen = modalStack.length > 0;
|
|
const currentModal = modalStack[modalStack.length - 1];
|
|
const modalContentType = currentModal?.contentType || "";
|
|
const entityId = currentModal?.entityId || "";
|
|
const entityLabel = currentModal?.entityLabel || "";
|
|
const closeOnClickOutside = currentModal?.closeOnClickOutside ?? true;
|
|
|
|
const openModal = useCallback(
|
|
(
|
|
contentType: string,
|
|
entityId?: string,
|
|
entityLabel?: string,
|
|
closeOnClickOutside?: boolean,
|
|
) => {
|
|
const newModal: ModalState = {
|
|
contentType,
|
|
entityId,
|
|
entityLabel,
|
|
closeOnClickOutside,
|
|
};
|
|
setModalStack((prev) => [...prev, newModal]);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const closeModal = useCallback(() => {
|
|
setModalStack((prev) => {
|
|
if (prev.length <= 1) {
|
|
return [];
|
|
}
|
|
return prev.slice(0, -1);
|
|
});
|
|
}, []);
|
|
|
|
const closeModals = useCallback((count: number) => {
|
|
setModalStack((prev) => {
|
|
const newLength = Math.max(0, prev.length - count);
|
|
return prev.slice(0, newLength);
|
|
});
|
|
}, []);
|
|
|
|
const clearAllModals = useCallback(() => {
|
|
setModalStack([]);
|
|
}, []);
|
|
|
|
const setModalState = useCallback((modalType: string, state: any) => {
|
|
setModalStates((prev) => ({
|
|
...prev,
|
|
[modalType]: state,
|
|
}));
|
|
}, []);
|
|
|
|
const getModalState = useCallback(
|
|
(modalType: string) => {
|
|
return modalStates[modalType];
|
|
},
|
|
[modalStates],
|
|
);
|
|
|
|
const clearModalState = useCallback((modalType: string) => {
|
|
setModalStates((prev) => {
|
|
const newStates = { ...prev };
|
|
delete newStates[modalType];
|
|
return newStates;
|
|
});
|
|
}, []);
|
|
|
|
const clearAllModalStates = useCallback(() => {
|
|
setModalStates({});
|
|
}, []);
|
|
|
|
return (
|
|
<ModalContext.Provider
|
|
value={{
|
|
isOpen,
|
|
openModal,
|
|
closeModal,
|
|
closeModals,
|
|
clearAllModals,
|
|
modalContentType,
|
|
entityId,
|
|
entityLabel,
|
|
closeOnClickOutside,
|
|
modalStates,
|
|
setModalState,
|
|
getModalState,
|
|
clearModalState,
|
|
clearAllModalStates,
|
|
}}
|
|
>
|
|
{children}
|
|
</ModalContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useModal = () => {
|
|
const context = useContext(ModalContext);
|
|
if (context === undefined) {
|
|
throw new Error("useModal must be used within a ModalProvider");
|
|
}
|
|
return context;
|
|
};
|