diff --git a/components/modal.js b/components/modal.js index 68d52acb6b..8f9cc79979 100644 --- a/components/modal.js +++ b/components/modal.js @@ -1,4 +1,4 @@ -import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react' +import { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef } from 'react' import Modal from 'react-bootstrap/Modal' import BackArrow from '@/svgs/arrow-left-line.svg' import { useRouter } from 'next/router' @@ -23,26 +23,27 @@ export function useShowModal () { } export default function useModal () { - const [modalContent, setModalContent] = useState(null) - const [modalOptions, setModalOptions] = useState(null) - const [modalStack, setModalStack] = useState([]) + const modalStack = useRef([]) + const [render, forceUpdate] = useReducer(x => x + 1, 0) + + const getCurrentContent = useCallback(() => { + return modalStack.current[modalStack.current.length - 1] + }, []) const onBack = useCallback(() => { - if (modalStack.length === 0) { - return setModalContent(null) - } - const previousModalContent = modalStack[modalStack.length - 1] - setModalStack(modalStack.slice(0, -1)) - modalOptions?.onClose?.() - return setModalContent(previousModalContent) - }, [modalStack, setModalStack, modalOptions?.onClose]) + getCurrentContent()?.options?.onClose?.() + modalStack.current.pop() + forceUpdate() + }, []) // this is called on every navigation due to below useEffect const onClose = useCallback(() => { - setModalContent(null) - setModalStack(ms => ms.length > 0 ? [] : ms) - modalOptions?.onClose?.() - }, [setModalStack, setModalContent, modalOptions?.onClose]) + while (modalStack.current.length) { + getCurrentContent()?.options?.onClose?.() + modalStack.current.pop() + } + forceUpdate() + }, []) const router = useRouter() useEffect(() => { @@ -51,45 +52,49 @@ export default function useModal () { }, [router.events, onClose]) const modal = useMemo(() => { - if (modalContent === null) { + if (modalStack.current.length === 0) { return null } - const className = modalOptions?.fullScreen ? 'fullscreen' : '' + + const content = getCurrentContent() + const { overflow, keepOpen, fullScreen } = content.options + const className = fullScreen ? 'fullscreen' : '' + return (
- {modalOptions?.overflow && + {overflow &&
- {modalOptions.overflow} + {overflow}
} - {modalStack.length > 0 ?
: null} + {modalStack.current.length > 1 ?
: null}
X
- {modalContent} + {content.node}
) - }, [modalContent, onClose, modalOptions, onBack, modalStack]) + }, [render]) const showModal = useCallback( (getContent, options) => { - if (modalContent) { - if (options?.replaceModal) { - setModalStack(stack => ([])) - } else setModalStack(stack => ([...stack, modalContent])) + const ref = { node: getContent(onClose), options } + if (options?.replaceModal) { + modalStack.current = [ref] + } else { + modalStack.current.push(ref) } - setModalOptions(options) - setModalContent(getContent(onClose)) + forceUpdate() }, - [modalContent, onClose] + [onClose] ) return [modal, showModal]