import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react' import Modal from 'react-bootstrap/Modal' import BackArrow from '@/svgs/arrow-left-line.svg' import { useRouter } from 'next/router' import ActionDropdown from './action-dropdown' export const ShowModalContext = createContext(() => null) export function ShowModalProvider ({ children }) { const [modal, showModal] = useModal() const contextValue = showModal return ( <ShowModalContext.Provider value={contextValue}> {children} {modal} </ShowModalContext.Provider> ) } export function useShowModal () { return useContext(ShowModalContext) } export default function useModal () { const [modalContent, setModalContent] = useState(null) const [modalOptions, setModalOptions] = useState(null) const [modalStack, setModalStack] = useState([]) 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]) // 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]) const router = useRouter() useEffect(() => { router.events.on('routeChangeStart', onClose) return () => router.events.off('routeChangeStart', onClose) }, [router.events, onClose]) const modal = useMemo(() => { if (modalContent === null) { return null } const className = modalOptions?.fullScreen ? 'fullscreen' : '' return ( <Modal onHide={modalOptions?.keepOpen ? null : onClose} show={!!modalContent} className={className} dialogClassName={className} contentClassName={className} > <div className='d-flex flex-row'> {modalOptions?.overflow && <div className={'modal-btn modal-overflow ' + className}> <ActionDropdown> {modalOptions.overflow} </ActionDropdown> </div>} {modalStack.length > 0 ? <div className='modal-btn modal-back' onClick={onBack}><BackArrow width={18} height={18} className='fill-white' /></div> : null} <div className={'modal-btn modal-close ' + className} onClick={onClose}>X</div> </div> <Modal.Body className={className}> {modalContent} </Modal.Body> </Modal> ) }, [modalContent, onClose, modalOptions, onBack, modalStack]) const showModal = useCallback( (getContent, options) => { if (modalContent) { if (options?.replaceModal) { setModalStack(stack => ([])) } else setModalStack(stack => ([...stack, modalContent])) } setModalOptions(options) setModalContent(getContent(onClose)) }, [modalContent, onClose] ) return [modal, showModal] }