import { useState, useCallback, useEffect } from '@wordpress/element';
import { applyFilters, addAction, removeAction } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import Header from './components/Header';
import Sidebar from './components/Sidebar';
import Welcome from './pages/Welcome';
import WidgetsPage from './pages/WidgetsPage';
import OtherSettings from './pages/OtherSettings';
import GetPro from './pages/GetPro';
import AboutInfo from './pages/AboutInfo';
import ProModulePlaceholder from './pages/ProModulePlaceholder';
import { appShell, bodyRow, mainContent } from './tw';
import Toast from './components/Toast';
import { getPlaceholderModules } from './utils';
const adminData = window.ultimateStoreKitAdminData || {};
const slugify = (label) =>
label.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
const getSettingsGroups = () => {
const widgets = adminData.widgets?.ultimate_store_kit_other_settings || [];
const groups = [];
widgets.forEach((w) => {
if (w.type === 'start_group') {
groups.push({ id: `settings-${slugify(w.label)}`, label: w.label });
}
});
return groups;
};
const settingsGroups = getSettingsGroups();
const getPageFromHash = () => {
const hash = window.location.hash.replace('#', '');
const pageName = hash.split('?')[0];
const placeholderIds = getPlaceholderModules().map((p) => p.id);
const proPages = applyFilters('usk.admin.pages', {});
const proPageIds = Object.keys(proPages);
const corePages = [
'welcome',
'widgets',
'woocommerce-widgets',
'edd-widgets',
'other-widgets',
'get-pro',
'about',
...settingsGroups.map((g) => g.id),
...placeholderIds,
...proPageIds,
];
const validPages = applyFilters('usk.admin.validPages', corePages);
return validPages.includes(pageName) ? pageName : 'welcome';
};
const App = () => {
const [activePage, setActivePage] = useState(getPageFromHash());
const [settings, setSettings] = useState(adminData.savedSettings || {});
const [isProActive, setIsProActive] = useState(!!adminData.isPro);
const [saving, setSaving] = useState(false);
const [notification, setNotification] = useState(null);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isDesktop, setIsDesktop] = useState(() => window.innerWidth > 1024);
// Allow pro (or any extension) to trigger toasts via doAction('usk.admin.notify', {...})
useEffect(() => {
const handleNotify = (data) => setNotification(data);
addAction('usk.admin.notify', 'usk-core', handleNotify);
return () => removeAction('usk.admin.notify', 'usk-core');
}, []);
// Listen for license activation/deactivation from Pro's LicensePage
useEffect(() => {
const handleLicenseChanged = (active) => {
setIsProActive(active);
window.ultimateStoreKitAdminData.isPro = active;
};
addAction('usk.admin.licenseChanged', 'usk-core', handleLicenseChanged);
return () => removeAction('usk.admin.licenseChanged', 'usk-core');
}, []);
useEffect(() => {
if (notification) {
const timer = setTimeout(() => setNotification(null), 3000);
return () => clearTimeout(timer);
}
}, [notification]);
useEffect(() => {
const handleHashChange = () => {
setActivePage(getPageFromHash());
};
window.addEventListener('hashchange', handleHashChange);
return () => window.removeEventListener('hashchange', handleHashChange);
}, []);
useEffect(() => {
// When pro plugin is installed, Get Pro is replaced by License.
// Redirect stale get-pro links to license (if registered) or welcome.
if (activePage === 'get-pro') {
const proPages = applyFilters('usk.admin.pages', {});
if (proPages.license || isProActive) {
const target = proPages.license ? 'license' : 'welcome';
setActivePage(target);
window.location.hash = `#${target}`;
}
}
}, [isProActive, activePage]);
useEffect(() => {
setIsSidebarOpen(false);
}, [activePage]);
useEffect(() => {
document.body.style.overflow = isSidebarOpen ? 'hidden' : '';
return () => {
document.body.style.overflow = '';
};
}, [isSidebarOpen]);
useEffect(() => {
const handleResize = () => {
const desktop = window.innerWidth > 1024;
setIsDesktop(desktop);
if (desktop) {
setIsSidebarOpen(false);
}
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
const handleToggleSidebar = useCallback((event) => {
if (event?.preventDefault) event.preventDefault();
if (event?.stopPropagation) event.stopPropagation();
setIsSidebarOpen((prev) => !prev);
}, []);
const saveSettings = useCallback(
(section, sectionSettings) => {
setSaving(true);
fetch(adminData.restUrl + 'settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': adminData.restNonce,
},
body: JSON.stringify({ section, settings: sectionSettings }),
})
.then((res) => {
if (!res.ok) throw res;
return res.json();
})
.then((data) => {
setSettings((prev) => ({
...prev,
[section]: sectionSettings,
}));
setNotification({
type: 'success',
message:
data?.message ||
__('Settings saved successfully.', 'ultimate-store-kit'),
});
})
.catch(() => {
setNotification({
type: 'error',
message: __(
'An error occurred while saving.',
'ultimate-store-kit'
),
});
})
.finally(() => {
setSaving(false);
});
},
[]
);
const renderPage = () => {
const widgets = adminData.widgets || {};
// Check pro-registered pages first
const proPages = applyFilters('usk.admin.pages', {});
if (proPages[activePage]) {
// If user doesn't have an active license, show placeholder for module pages
if (!isProActive) {
const placeholders = getPlaceholderModules();
const placeholder = placeholders.find((p) => p.id === activePage);
if (placeholder) {
return