import { __, sprintf } from '@wordpress/i18n'; import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { Button } from './index.jsx'; import EasySetupWizard from '../EasySetupWizard.jsx'; import useSettingsMeta from '../../hooks/useSettingsMeta.js'; const settingsRoutes = [ '/side-cart', '/checkout', '/abandoned-cart', '/modules', '/settings', ]; export default function Layout( { children } ) { const location = useLocation(); const [ dirty, setDirty ] = useState( false ); const [ saving, setSaving ] = useState( false ); const [ saved, setSaved ] = useState( false ); const [ saveError, setSaveError ] = useState( '' ); const hasSettingsActions = settingsRoutes.includes( location.pathname ); const meta = useSettingsMeta( hasSettingsActions ); const shellRef = useRef( null ); const actionsRef = useRef( null ); const savedAt = meta.data?.last_saved_at_formatted || ( meta.isLoading ? __( 'Loading…', 'arrayfunnel' ) : meta.isError ? __( 'Unavailable', 'arrayfunnel' ) : __( 'Not recorded yet', 'arrayfunnel' ) ); useLayoutEffect( () => { if ( ! hasSettingsActions || ! actionsRef.current ) return; const shell = shellRef.current; const measure = () => { if ( ! actionsRef.current ) return; shell.style.setProperty( '--arrayfunnel-actions-height', `${ actionsRef.current.getBoundingClientRect().height + 30 }px` ); }; measure(); const observer = new window.ResizeObserver( measure ); observer.observe( actionsRef.current ); return () => { observer.disconnect(); shell.style.removeProperty( '--arrayfunnel-actions-height' ); }; }, [ hasSettingsActions ] ); useEffect( () => { setDirty( false ); setSaved( false ); setSaveError( '' ); }, [ location.pathname ] ); // WordPress cannot read fragment routes when it marks the current submenu. useEffect( () => { const activePath = location.pathname.startsWith( '/order-bumps/' ) ? '/order-bumps' : location.pathname; const links = document.querySelectorAll( '#toplevel_page_arrayfunnel .wp-submenu a' ); const restore = Array.from( links, ( link ) => { const item = link.closest( 'li' ); const previousLinkCurrent = link.classList.contains( 'current' ); const previousItemCurrent = item?.classList.contains( 'current' ); const previousAriaCurrent = link.getAttribute( 'aria-current' ); const linkPath = new URL( link.href, window.location.href ).hash.slice( 1 ) || '/'; const isCurrent = linkPath === activePath; link.classList.toggle( 'current', isCurrent ); item?.classList.toggle( 'current', isCurrent ); if ( isCurrent ) { link.setAttribute( 'aria-current', 'page' ); } else { link.removeAttribute( 'aria-current' ); } return () => { link.classList.toggle( 'current', previousLinkCurrent ); item?.classList.toggle( 'current', previousItemCurrent ); if ( previousAriaCurrent === null ) { link.removeAttribute( 'aria-current' ); } else { link.setAttribute( 'aria-current', previousAriaCurrent ); } }; } ); return () => restore.forEach( ( reset ) => reset() ); }, [ location.pathname ] ); useEffect( () => { const handleDirtyState = ( event ) => { const nextDirty = Boolean( event?.detail?.dirty ); if ( nextDirty ) { setSaved( false ); } setDirty( nextDirty ); }; window.addEventListener( 'arrayfunnel:dirty-state', handleDirtyState ); return () => window.removeEventListener( 'arrayfunnel:dirty-state', handleDirtyState ); }, [] ); async function handleSave() { if ( ! dirty || saving ) { return; } const saveTasks = []; window.dispatchEvent( new window.CustomEvent( 'arrayfunnel:save-current-page', { detail: { register( task ) { if ( task ) { saveTasks.push( Promise.resolve( task ) ); } }, }, } ) ); if ( saveTasks.length === 0 ) { return; } setSaving( true ); setSaved( false ); setSaveError( '' ); const results = await Promise.allSettled( saveTasks ); setSaving( false ); const failure = results.find( ( result ) => result.status === 'rejected' ); if ( failure ) { setSaveError( failure.reason?.message || __( 'Could not save settings. Please try again.', 'arrayfunnel' ) ); return; } setDirty( false ); setSaved( true ); } function handleDiscard() { if ( ! dirty || saving ) return; window.dispatchEvent( new window.CustomEvent( 'arrayfunnel:discard-current-page' ) ); setSaved( false ); setSaveError( '' ); } return (
{ children }
{ hasSettingsActions && (

{ sprintf( /* translators: %s: last successful settings save in WordPress date and time format. */ __( 'Updated at: %s', 'arrayfunnel' ), savedAt ) }

{ saveError || ( saved ? __( 'Settings saved.', 'arrayfunnel' ) : dirty ? __( 'Unsaved changes', 'arrayfunnel' ) : __( 'No unsaved changes', 'arrayfunnel' ) ) }
) }
); }