Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 88 additions & 25 deletions modules/admin-home/assets/js/hello-elementor-conversion-banner.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import apiFetch from '@wordpress/api-fetch';
import { createRoot } from 'react-dom/client';
import { useLayoutEffect } from 'react';
import { ThemeProvider } from '@elementor/ui/styles';
import { Welcome } from './components/paper/welcome';
import { AdminProvider } from './providers/admin-provider';
import Box from '@elementor/ui/Box';

const App = () => {
const App = ({ config, container }) => {
useLayoutEffect(() => {
container.style.visibility = 'visible';
}, [container]);

return (
<ThemeProvider colorScheme="light">
<AdminProvider>
<AdminProvider initialSettings={config}>
<Welcome
sx={{
mt: 2,
Expand All @@ -25,28 +30,86 @@ const App = () => {
);
};

document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('ehe-admin-cb');

if (container) {
const { beforeWrap = false } = window.ehe_cb;
const { selector, before = false } = window.ehe_cb.data;
const headerEnd = document.querySelector(selector);

if (headerEnd) {
if (beforeWrap) {
const wrapElement = document.querySelector('.wrap');
if (wrapElement) {
wrapElement.insertAdjacentElement('beforebegin', container);
}
} else if (before) {
headerEnd.insertAdjacentElement('beforebegin', container);
} else {
headerEnd.insertAdjacentElement('afterend', container);
}
const insertBanner = (container, placement) => {
const { beforeWrap = false, selector, before = false } = placement;

if (beforeWrap) {
const wrapElement = document.querySelector('.wrap');

if (!wrapElement) {
return false;
}

wrapElement.insertAdjacentElement('beforebegin', container);
return true;
}

if (before) {
const anchor = document.querySelector(selector);

if (!anchor) {
return false;
}

const root = createRoot(container);
root.render(<App />);
anchor.insertAdjacentElement('beforebegin', container);
return true;
}

const pageTitleAction = document.querySelector('.wrap .page-title-action');

if (pageTitleAction) {
pageTitleAction.insertAdjacentElement('afterend', container);
return true;
}

const headerEnd = document.querySelector(selector);

if (!headerEnd) {
return false;
}

headerEnd.insertAdjacentElement('afterend', container);
return true;
};

const init = async () => {
if ('undefined' === typeof window.ehe_cb) {
return;
}

let config;

try {
const response = await apiFetch({
path: '/elementor-hello-elementor/v1/admin-settings',
});
config = response.config;
} catch (e) {
return;
}

if (!config?.welcome?.title) {
return;
}
});

const { beforeWrap = false } = window.ehe_cb;
const { selector, before = false } = window.ehe_cb.data;

const container = document.createElement('div');
container.id = 'ehe-admin-cb';
container.className = 'ehe-admin-cb';
container.style.visibility = 'hidden';

if (!insertBanner(container, { beforeWrap, selector, before })) {
return;
}

const root = createRoot(container);
root.render(<App config={config} container={container} />);
};

if ('loading' === document.readyState) {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
14 changes: 10 additions & 4 deletions modules/admin-home/assets/js/providers/admin-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@ import apiFetch from '@wordpress/api-fetch';

export const AdminContext = createContext();

export const AdminProvider = ({ children }) => {
const [isLoading, setIsLoading] = React.useState(true);
const [adminSettings, setAdminSettings] = React.useState({});
export const AdminProvider = ({ children, initialSettings = null }) => {
const [isLoading, setIsLoading] = React.useState(!initialSettings);
const [adminSettings, setAdminSettings] = React.useState(
initialSettings || {},
);

useEffect(() => {
if (initialSettings) {
return;
}

apiFetch({ path: '/elementor-hello-elementor/v1/admin-settings' })
.then((settings) => {
setAdminSettings(settings.config);
})
.finally(() => {
setIsLoading(false);
});
}, []);
}, [initialSettings]);

return (
<AdminContext.Provider
Expand Down
11 changes: 0 additions & 11 deletions modules/admin-home/components/conversion-banner.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ class Conversion_Banner {
const USER_META_KEY = '_hello_elementor_install_notice';
const AJAX_ACTION = 'ehe_dismiss_theme_notice';

private function render_conversion_banner() {
?>
<div id="ehe-admin-cb" style="width: calc(100% - 48px)">
</div>
<?php
}

private function get_allowed_admin_pages(): array {
return [
'dashboard' => [ 'selector' => '#wpbody #wpbody-content .wrap h1' ],
Expand Down Expand Up @@ -199,10 +192,6 @@ public function __construct() {
return;
}

add_action( 'in_admin_header', function () {
$this->render_conversion_banner();
}, 11 );

add_action( 'admin_enqueue_scripts', function () use ( $conversion_banner_active ) {
$this->enqueue_scripts( $conversion_banner_active );
} );
Expand Down
149 changes: 149 additions & 0 deletions tests/playwright/tests/conversion-banner-layout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { parallelTest as test } from '../parallelTest.ts';
import { expect } from '@playwright/test';
import WpAdminPage from '../pages/wp-admin-page.ts';
import { timeouts } from '../config/timeouts.ts';

const emptyWelcomeAdminSettings = {
config: {
welcome: [],
config: {
nonceInstall: 'test-nonce',
slug: 'elementor',
},
},
};

test.describe('Conversion banner flows [ED-25235]', () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do have a ticket 25235?

test('Pages list does not mount banner when welcome config is empty', async ({
page,
apiRequests,
}, testInfo) => {
await page.route(
'**/elementor-hello-elementor/v1/admin-settings**',
async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(emptyWelcomeAdminSettings),
});
},
);

const wpAdmin = new WpAdminPage(page, testInfo, apiRequests);

await wpAdmin.login();

await page.goto('/wp-admin/edit.php?post_type=page', {
waitUntil: 'networkidle',
timeout: timeouts.longAction,
});

await page.waitForSelector('.wrap h1.wp-heading-inline', {
timeout: timeouts.longAction,
});

await page.waitForTimeout(timeouts.longAction / 5);

await expect(page.locator('#ehe-admin-cb')).toHaveCount(0);

const headingBox = await page
.locator('.wrap h1.wp-heading-inline')
.boundingBox();
const actionBox = await page
.locator('.wrap .page-title-action')
.first()
.boundingBox();

expect(headingBox).not.toBeNull();
expect(actionBox).not.toBeNull();

if (headingBox && actionBox) {
expect(actionBox.y).toBeLessThan(headingBox.y + headingBox.height + 8);
}
});

test('Hello settings page still loads without conversion banner regressions', async ({
page,
apiRequests,
}, testInfo) => {
const wpAdmin = new WpAdminPage(page, testInfo, apiRequests);

await wpAdmin.login();

await page.goto('/wp-admin/admin.php?page=hello-elementor-settings', {
waitUntil: 'networkidle',
timeout: timeouts.longAction,
});

await expect(page.locator('#ehe-admin-settings')).toBeVisible({
timeout: timeouts.longAction,
});

const bannerCount = await page.locator('#ehe-admin-cb').count();

if (bannerCount > 0) {
const action = page.locator('.wrap .page-title-action').first();
const banner = page.locator('#ehe-admin-cb');

if ((await action.count()) > 0) {
const isAfterAction = await page.evaluate(() => {
const actionNode = document.querySelector('.wrap .page-title-action');
const bannerNode = document.getElementById('ehe-admin-cb');

return Boolean(
actionNode &&
bannerNode &&
actionNode.nextElementSibling === bannerNode,
);
});

expect(isAfterAction).toBe(true);
}
}
});

test('Plugins page keeps native title row when banner is absent', async ({
page,
apiRequests,
}, testInfo) => {
const wpAdmin = new WpAdminPage(page, testInfo, apiRequests);

await wpAdmin.login();

await page.goto('/wp-admin/plugins.php', {
waitUntil: 'networkidle',
timeout: timeouts.longAction,
});

await page.waitForSelector('.wrap h1', {
timeout: timeouts.longAction,
});

await page.waitForTimeout(timeouts.longAction / 5);

const banner = page.locator('#ehe-admin-cb');
const bannerCount = await banner.count();

if (bannerCount > 0) {
const heading = page.locator('.wrap h1').first();
const action = page.locator('.wrap .page-title-action').first();

if ((await action.count()) > 0) {
const isAfterAction = await page.evaluate(() => {
const actionNode = document.querySelector('.wrap .page-title-action');
const bannerNode = document.getElementById('ehe-admin-cb');

return Boolean(
actionNode &&
bannerNode &&
actionNode.nextElementSibling === bannerNode,
);
});

expect(isAfterAction).toBe(true);
}

await expect(heading).toBeVisible();
}
});
});
Loading