import {useEffect, useState} from '@wordpress/element'; import {__} from '@wordpress/i18n'; import {Button, Dialog, Modal, ModalOverlay} from 'react-aria-components'; import ModalCloseIcon from './ModalClose'; import EmbedFrame from '@givewp/forms/shared/EmbedFrame'; import './styles.scss'; import '../EntitySelector/styles/index.scss'; import {FocusScope} from 'react-aria'; /** * @since 4.17.0 add formUrl, where the fallback link points when the form is slow to load. * @since 4.3.0 */ type ModalFormProps = { dataSrc: string; embedId: string; buttonText: string; isFormRedirect: boolean; formViewUrl: string; formUrl?: string; }; /** * @since 4.17.0 render the iframe through EmbedFrame; a form that is slow to load also offers a link. * @since 4.17.0 Share the launcher's pending state markup and styles with the external embed. * @since 4.3.0 */ export default function ModalForm({ dataSrc, embedId, buttonText, isFormRedirect, formViewUrl, formUrl, }: ModalFormProps) { const [dataSrcUrl, setDataSrcUrl] = useState(dataSrc); const [isOpen, setIsOpen] = useState(isFormRedirect); const [isLoading, setLoading] = useState(false); const [isEntering, setEntering] = useState(false); useEffect(() => { const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape' && isOpen) { closeModal(); } }; document.addEventListener('keydown', handleEscape); return () => { document.removeEventListener('keydown', handleEscape); }; }, [isOpen]); // Preload the iframe document useEffect(() => { const selector = `link[rel="preload"][href="${dataSrcUrl}"][as="document"]`; const existingLink = document.querySelector(selector); if (!existingLink) { const link = document.createElement('link'); link.rel = 'preload'; link.href = dataSrcUrl; link.as = 'document'; document.head.appendChild(link); } return () => { const addedLink = document.querySelector(selector); if (addedLink) { document.head.removeChild(addedLink); } }; }, [dataSrcUrl]); useEffect(() => { if (isEntering && !isLoading) { resetEntering(); } }, [isEntering, isLoading]); // Offline gateways like Stripe refresh the page and need to programmatically // open the confirmation page from the modal. const resetDataSrcUrl = () => { if (!isOpen && isFormRedirect) { setDataSrcUrl(formViewUrl); } }; const openModal = () => { setEntering(true); setIsOpen(true); setLoading(true); resetDataSrcUrl(); }; const closeModal = () => { setIsOpen(false); setLoading(false); resetDataSrcUrl(); }; const resetEntering = () => { setTimeout(() => { setEntering(false); }, 2000); }; return ( <>
setLoading(false)} onSlow={() => setLoading(false)} />
); }