import React, { createContext, useContext, useReducer } from 'react'; import { isAbsoluteUrl } from '@availity/resolve-url'; import { Dialog, DialogTitle, DialogActions } from '@availity/mui-dialog'; import { Button } from '@availity/mui-button'; import { getUrl, getTarget, updateUrl } from '../helpers'; import { updateTopApps } from '../topApps'; import { DisclaimerModal } from './DisclaimerModal'; import { MultiPayerModal } from './MultiPayerModal'; import type { ModalProviderState, ModalState, DisclaimerOnSubmitProps, MultiPayerOnSubmitProps, ModalOptions, ModalTypes, ModalContextType, ModalReducerType, } from './modal-types'; import { isModalOptions, isModalState } from './modal-types'; export const MODAL_INITIAL_STATE = { isOpen: false, modalOptions: undefined, modalState: { selectedOption: { id: '', name: '' } }, selectedModal: {}, }; export const ModalContext = createContext(null); export const useModal = () => { const ctx = useContext(ModalContext); if (!ctx) throw new Error('ModalContext be used inside a Provider'); return ctx; }; export const MODAL_TYPES = { DISCLAIMER: { body: DisclaimerModal, buttonProps: () => ({ children: 'Accept', }), onSubmit: ({ link, id: spaceId }: DisclaimerOnSubmitProps) => { window.open(link.url?.[0] === '/' ? updateUrl(link.url, 'spaceId', spaceId) : link.url, link.target); }, }, MULTI_PAYER: { body: MultiPayerModal, buttonProps: ({ selectedOption }: ModalState) => ({ children: 'Continue', disabled: selectedOption === undefined, }), onSubmit: ( { metadata, link, id: spaceId, name }: MultiPayerOnSubmitProps, modalState: ModalState, dispatch: React.Dispatch<{ [x: string]: any; type: any }> ) => { if (metadata?.disclaimerId) { dispatch({ type: 'OPEN_DISCLAIMER_MODAL', disclaimerId: metadata.disclaimerId, link, id: spaceId, name }); return; } const target = getTarget(link.target); if (link.url) { window.open( !isAbsoluteUrl(link.url) ? getUrl(updateUrl(link.url, 'spaceId', modalState.selectedOption.id), false, false) : link.url, target ); } }, }, }; export const modalActions = { RESET: (): ModalProviderState => MODAL_INITIAL_STATE, OPEN_DISCLAIMER_MODAL: (state: ModalProviderState, modalOptions: ModalOptions): ModalProviderState => ({ ...state, isOpen: true, selectedModal: MODAL_TYPES.DISCLAIMER, modalOptions: { ...modalOptions, type: modalOptions.spaceType }, }), OPEN_MULTI_PAYER_MODAL: (state: ModalProviderState, modalOptions: ModalOptions): ModalProviderState => ({ ...state, isOpen: true, selectedModal: MODAL_TYPES.MULTI_PAYER, modalOptions: { ...modalOptions, type: modalOptions.spaceType, }, }), UPDATE_MODAL_STATE: (state: ModalProviderState, modalState: ModalState): ModalProviderState => ({ ...state, modalState, }), }; export const modalReducer: ModalReducerType = (state, { type, ...action }) => { if (type === 'RESET') return modalActions.RESET(); if (isModalOptions(action)) { if (type === 'OPEN_MULTI_PAYER_MODAL') return modalActions.OPEN_MULTI_PAYER_MODAL(state, action); if (type === 'OPEN_DISCLAIMER_MODAL') return modalActions.OPEN_DISCLAIMER_MODAL(state, action); } else if (isModalState(action) && type === 'UPDATE_MODAL_STATE') return modalActions.UPDATE_MODAL_STATE(state, action); return state; }; export const ModalProvider = ({ children }: { children?: React.ReactNode }) => { const [{ selectedModal, modalOptions, modalState, isOpen }, dispatch] = useReducer(modalReducer, MODAL_INITIAL_STATE); const toggle = () => dispatch({ type: 'RESET' }); const buttonProps = selectedModal?.buttonProps && selectedModal?.buttonProps({ ...modalState, modalOptions }); const Body = selectedModal?.body; return ( dispatch({ type: `OPEN_${modalType}`, ...modalOptions }) } > {modalOptions?.title} {Body && ( dispatch({ type: 'UPDATE_MODAL_STATE', ...newState })} state={modalState} /> )} {children} ); };