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 ; } } const ProPageComponent = proPages[activePage]; return ; } // Check placeholder modules (upsell for non-pro users) const placeholders = getPlaceholderModules(); const placeholder = placeholders.find((p) => p.id === activePage); if (placeholder) { return ; } switch (activePage) { case 'welcome': return ( ); case 'widgets': case 'woocommerce-widgets': case 'edd-widgets': case 'other-widgets': { const widgetTypeMap = { 'woocommerce-widgets': 'wc', 'edd-widgets': 'edd', 'other-widgets': 'other', 'widgets': 'wc' }; return ( ); } case 'get-pro': return isProActive ? ( ) : ( ); case 'about': return ; default: { const settingsGroup = settingsGroups.find((g) => g.id === activePage); if (settingsGroup) { return ( ); } return ; } } }; return (
setNotification(null)} />
setIsSidebarOpen(false)} settingsGroups={settingsGroups} />
{renderPage()}
); }; export default App;