import { useCallback, useEffect, useState } from 'react'; import { __, _x, sprintf } from '@wordpress/i18n'; import { api, cfg } from './api.js'; import * as UI from './ui.jsx'; import { Button, Icon, Notice, Spinner, Toasts } from './ui.jsx'; import Dashboard from './screens/Dashboard.jsx'; import Settings from './screens/Settings.jsx'; import Hosted from './screens/Hosted.jsx'; import Notifications from './screens/Notifications.jsx'; import Extend from './screens/Extend.jsx'; import Help from './screens/Help.jsx'; const CORE = { dashboard: Dashboard, settings: Settings, hosted: Hosted, notifications: Notifications, extend: Extend, help: Help }; // Screens in menu order come from PHP (Core's plus any add-on's via `dashbread_admin_screens`). // Core components are wired here; an add-on's bundle (enqueued after 'dashbread-admin') calls // window.DashbreadAdmin.registerScreen('license', Component) and the app re-renders. const SCREENS = {}; // Product name and marks (the White Label add-on sets them; Core says Dashbread). const brand = Object.assign({ name: 'Dashbread', logo: '', tagline: cfg.pro ? sprintf( /* translators: %s: Dashbread Core version number */ __('Core %s · Pro installed', 'dashbread'), cfg.version ) : sprintf( /* translators: %s: Dashbread Core version number */ __('Core %s · Pro not installed', 'dashbread'), cfg.version ) }, cfg.brand || {}); (cfg.screens || []).forEach((s) => { SCREENS[s.id] = { label: s.label, slug: s.slug, C: CORE[s.id] || null }; }); const screenListeners = new Set(); function registerScreen(id, Component) { // PHP decides which screens exist (menus, capabilities, entitlements). A component for a screen // PHP didn't list is kept aside, never given a tab. if (!SCREENS[id]) return; SCREENS[id].C = Component; screenListeners.forEach((l) => l()); } window.DashbreadAdmin = Object.assign(window.DashbreadAdmin || {}, { registerScreen, ui: UI, api, React: window.React }); function Pending() { return ; } function screenFromUrl(fallback) { const page = new URLSearchParams(location.search).get('page') || ''; return Object.keys(SCREENS).find((k) => SCREENS[k].slug === page) || fallback; } /** Keep the wp-admin submenu highlight in sync when switching screens client-side. */ function syncWpMenu(slug) { document.querySelectorAll('#toplevel_page_dashbread .wp-submenu li').forEach((li) => { const a = li.querySelector('a'); const on = a && a.getAttribute('href') === 'admin.php?page=' + slug; li.classList.toggle('current', !!on); a && a.classList.toggle('current', !!on); }); } function readMode() { try { return localStorage.getItem('dashbread-admin-mode') || 'light'; } catch (e) { return 'light'; } } export default function App({ initial }) { const [screen, setScreen] = useState(() => screenFromUrl(initial)); const [data, setData] = useState(null); const [error, setError] = useState(''); const [mode, setMode] = useState(readMode); const [, bump] = useState(0); useEffect(() => { const l = () => bump((n) => n + 1); screenListeners.add(l); return () => screenListeners.delete(l); }, []); const load = useCallback(async () => { setError(''); try { setData(await api.bootstrap()); } catch (e) { setError(e.message); } }, []); useEffect(() => { load(); }, [load]); useEffect(() => { document.documentElement.setAttribute('data-sui-preset', 'console'); document.documentElement.setAttribute('data-sui-mode', mode); try { localStorage.setItem('dashbread-admin-mode', mode); } catch (e) {} return () => { document.documentElement.removeAttribute('data-sui-mode'); document.documentElement.removeAttribute('data-sui-preset'); }; }, [mode]); const go = useCallback((key) => { if (!SCREENS[key]) return; setScreen(key); history.pushState({ dashbread: key }, '', cfg.adminUrl + '?page=' + SCREENS[key].slug); syncWpMenu(SCREENS[key].slug); window.scrollTo(0, 0); }, []); useEffect(() => { const h = () => setScreen(screenFromUrl('dashboard')); window.addEventListener('popstate', h); return () => window.removeEventListener('popstate', h); }, []); const Screen = (SCREENS[screen] && SCREENS[screen].C) || Pending; return (
{brand.logo ? : {brand.name.charAt(0).toUpperCase()}}
{brand.name}
{brand.tagline &&
{brand.tagline}
}
{data && }
{error && {__('Could not load.', 'dashbread')} {error} } {!data && !error && } {data && }
); }