|
| 1 | +/* global MutationObserver */ |
| 2 | +import { createPortal, useEffect, useState } from '@wordpress/element'; |
| 3 | +import { Button } from '@wordpress/components'; |
| 4 | +import { __ } from '@wordpress/i18n'; |
| 5 | +import { wordpress } from '@wordpress/icons'; |
| 6 | + |
| 7 | +/** |
| 8 | + * A button to exit the user to the plugin dashboard. |
| 9 | + * The button is injected before the save button of the site editor. |
| 10 | + * @return {React.ReactNode} Dashboard button component portal. |
| 11 | + */ |
| 12 | +const DashboardButton = () => { |
| 13 | + const [ dashboardButtonContainer, setDashboardButtonContainer ] = useState( null ); |
| 14 | + |
| 15 | + useEffect( () => { |
| 16 | + /** |
| 17 | + * Create and inject the dashboard button container into the site editor header actions. |
| 18 | + * @return {void} |
| 19 | + */ |
| 20 | + const createDashboardButtonContainer = () => { |
| 21 | + const siteEditor = document.querySelector( '#site-editor' ); |
| 22 | + if ( ! siteEditor ) { |
| 23 | + return; |
| 24 | + } |
| 25 | + |
| 26 | + const siteEditorHeaderActions = siteEditor.querySelector( '.editor-header .editor-header__settings' ); |
| 27 | + if ( ! siteEditorHeaderActions ) { |
| 28 | + return; |
| 29 | + } |
| 30 | + |
| 31 | + // Prevent duplicates if the container already exists. |
| 32 | + const existingContainer = siteEditorHeaderActions.querySelector( '.nfd-design-studio-dashboard-button' ); |
| 33 | + if ( existingContainer ) { |
| 34 | + setDashboardButtonContainer( existingContainer ); |
| 35 | + return; |
| 36 | + } |
| 37 | + |
| 38 | + // Create the container element. |
| 39 | + const dashboardButtonContainerElement = document.createElement( 'div' ); |
| 40 | + dashboardButtonContainerElement.className = 'nfd-design-studio-dashboard-button'; |
| 41 | + // Insert before the save button |
| 42 | + const siteEditorSaveButton = siteEditorHeaderActions.querySelector( '.editor-post-publish-button__button' ); |
| 43 | + if ( siteEditorSaveButton && siteEditorSaveButton.parentNode ) { |
| 44 | + siteEditorSaveButton.parentNode.insertBefore( dashboardButtonContainerElement, siteEditorSaveButton ); |
| 45 | + } else { |
| 46 | + siteEditorHeaderActions.appendChild( dashboardButtonContainerElement ); |
| 47 | + } |
| 48 | + |
| 49 | + setDashboardButtonContainer( dashboardButtonContainerElement ); |
| 50 | + }; |
| 51 | + createDashboardButtonContainer(); |
| 52 | + |
| 53 | + // Observer: watch for DOM changes and ensure dashboard button presence. |
| 54 | + const observer = new MutationObserver( () => { |
| 55 | + // Use a timeout to debounce rapid DOM changes. |
| 56 | + setTimeout( () => { |
| 57 | + if ( ! dashboardButtonContainer ) { |
| 58 | + createDashboardButtonContainer(); |
| 59 | + } |
| 60 | + }, 100 ); |
| 61 | + } ); |
| 62 | + observer.observe( document.body, { |
| 63 | + childList: true, |
| 64 | + subtree: true, |
| 65 | + } ); |
| 66 | + |
| 67 | + // On unmount: remove the container and disconnect the observer. |
| 68 | + return () => { |
| 69 | + observer.disconnect(); |
| 70 | + if ( dashboardButtonContainer && dashboardButtonContainer.parentNode ) { |
| 71 | + dashboardButtonContainer.parentNode.removeChild( dashboardButtonContainer ); |
| 72 | + } |
| 73 | + }; |
| 74 | + // eslint-disable-next-line react-hooks/exhaustive-deps |
| 75 | + }, [] ); |
| 76 | + |
| 77 | + const getPluginDashboardPageUrl = () => { |
| 78 | + // Get the admin URL from the NewfoldRuntime. |
| 79 | + const adminUrl = window.NewfoldRuntime?.admin_url; |
| 80 | + if ( adminUrl ) { |
| 81 | + const brand = window.NewfoldRuntime?.context?.brand?.name; |
| 82 | + if ( brand ) { |
| 83 | + return `${ adminUrl }admin.php?page=${ brand }&referrer=nfd-design-studio`; |
| 84 | + } |
| 85 | + |
| 86 | + return adminUrl; |
| 87 | + } |
| 88 | + |
| 89 | + // Fallback to the default WordPress admin URL. |
| 90 | + return '/wp-admin/'; |
| 91 | + }; |
| 92 | + |
| 93 | + const dashboardButtonComponent = ( |
| 94 | + <Button |
| 95 | + variant="secondary" |
| 96 | + size="compact" |
| 97 | + icon={ wordpress } |
| 98 | + disabled={ false } |
| 99 | + href={ getPluginDashboardPageUrl() } |
| 100 | + className="nfd-design-studio-dashboard-button" |
| 101 | + > |
| 102 | + { __( 'Dashboard' ) } |
| 103 | + </Button> |
| 104 | + ); |
| 105 | + |
| 106 | + return dashboardButtonContainer ? createPortal( dashboardButtonComponent, dashboardButtonContainer ) : null; |
| 107 | +}; |
| 108 | + |
| 109 | +export default DashboardButton; |
0 commit comments