From 4089ba01e0881c89a72332e13bc3a80b6bddec2a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 29 Jun 2026 22:15:55 +0000
Subject: [PATCH] =DashboardManager overhaul. A bit easier to modify the output of pages. Still have to get the account pages to work as expected, as well as verify the integrations and others are working - but registrar/content pages work as expected. Also fixed up the table generation in CRUD.js and CRUDSkeleton.php

---
 inc/managers/Dashboard/DashboardManager.php |  539 +++++++++++++++++++++++++++++++----------------------------
 1 files changed, 287 insertions(+), 252 deletions(-)

diff --git a/inc/managers/Dashboard/DashboardManager.php b/inc/managers/Dashboard/DashboardManager.php
index 2c4ae50..3ef40f4 100644
--- a/inc/managers/Dashboard/DashboardManager.php
+++ b/inc/managers/Dashboard/DashboardManager.php
@@ -5,42 +5,57 @@
 use JVBase\forms\TaxonomySelector;
 use JVBase\base\Site;
 use JVBase\managers\Cache;
-use JVBase\managers\RoleManager;use JVBase\registrar\Registrar;
+use JVBase\managers\IconsManager;use JVBase\managers\RoleManager;use JVBase\meta\Form;use JVBase\meta\Meta;use JVBase\registrar\Fields;use JVBase\registrar\Registrar;
 use JVBase\ui\Navigation;
 
 if (!defined('ABSPATH')) {
 	exit;
 }
 class DashboardManager {
+	public static string $based;
+	protected string $slug = 'dash';
+	protected string $baseURl;
+	protected array $currentUserPages = [];
 	protected array $pages = [];
 	protected array $sections = [];
 	protected Cache $cache;
 	public function __construct() {
+		self::$based = BASE.$this->slug;
 		$this->cache = Cache::for('dashboard')->connect('post');
 		if (JVB_TESTING) {
 			$this->cache->flush();
 		}
+		$this->registerDashboard();
 		$this->buildPages();
 		$this->buildSections();
+		$this->setCurrentUserPages();
 		//Since this is loaded via JVBase, it's already running on init
-		$this->registerDashboard();
 		$this->registerHooks();
+
+		$doit = apply_filters('jvb_base_dashboard_dash', true);
+		if ($doit) {
+			add_action(BASE.'dashboard_page_dash', [$this, 'renderMain'], 10);
+		}
+		add_action(BASE.'dashboard_page_account', [$this, 'renderAccount'], 10);
 	}
+
 	protected function registerDashboard():void
 	{
-		$dash = Registrar::forPost('dash', 'Dashboard', 'Dashboards');
+		$dash = Registrar::forPost($this->slug, 'Dashboard', 'Dashboards');
 		$dash->setIcon('gauge')
 			->make([
-				'show_in_admin_bar'	=> false,
 				'rewrite'		=> [
-					'slug'			=> 'dash',
+					'slug'			=> $this->slug,
 					'with_front' 	=> false,
 				],
 				'supports'		=> [ 'title', 'editor', 'custom-fields'],
-				'hierarchical'	=> true
+				'hierarchical'	=> true,
+				'has_archive'	=> true,
 			])->setAll([
 				'system'
 			]);
+
+		$dash->register();
 	}
 
 	protected function registerHooks():void
@@ -54,14 +69,12 @@
 	}
 		public function handleRedirects():void
 		{
-			if (!is_singular(BASE.'dash') && !is_post_type_archive(BASE.'dash') && !is_404()) {
+			if (!is_singular(self::$based) && !is_post_type_archive(self::$based) && !is_404()) {
 				return;
 			}
 
-
 			if (!is_404()) {
 				if (!is_user_logged_in()) {
-					error_log('Redirecting to login - user not logged in');
 					$this->redirectToLogin();
 				} elseif (!isOurPeople() && !current_user_can('manage_options')) {
 					$this->redirectToHome();
@@ -70,40 +83,46 @@
 					if (array_key_exists($page, ['', 'dash'])) {
 						return;
 					}
-					if (!array_key_exists($page, $this->pages)) {
+					$page = $this->getCurrentPage();
+					if (!in_array($page, $this->pages)) {
+						error_log('Looking for page: '.$page. ' in: '.print_r($this->pages, true));
 						error_log('[DashboardManager]::handleRedirect could not find page for '.$page);
 						return;
 					}
-					$permission = $this->pages[$page]->getPermission();
+					$permission = $page->getPermission();
 					if (!empty($permission) && !current_user_can($permission)) {
 						error_log('[DashboardManager]::handleRedirect User cannot manage '.$page);
 						$this->redirectToDashboard();
 					}
 				}
+				return;
 			}
 			global $wp;
-			if (str_starts_with($wp->request, 'dash/') || $wp->request === 'dash') {
+			if (is_404() && str_starts_with($wp->request, $this->slug.'/') || $wp->request === $this->slug) {
 				error_log('404 on dashboard URL, redirecting to dashboard home');
 				$this->redirectToDashboard();
 			}
 		}
 		public function dashboardTemplates(string $template):string
 		{
-			if (!is_singular(BASE.'dash') && !is_post_type_archive(BASE.'dash')) {
+			if (!is_singular(self::$based) && !is_post_type_archive(self::$based)) {
 				return $template;
 			}
 			$page = $this->getCurrentPage();
-			if (!empty($page->getIcon())) {
-				add_filter('jvbLoadingIcon', $page->getIcon());
+
+			if ($page && !empty($page->getIcon())) {
+				add_filter('jvbLoadingIcon', [$page, 'getIcon']);
 			}
 			ob_start();
 			jvbInlineStyles('nav');
 			jvbInlineStyles('dash');
 			jvbInlineStyles('forms');
 			$this->renderHeader();
-			$page->render();
+			echo $page->render();
 			$this->renderFooter();
-			return ob_get_clean();
+			$got = ob_get_clean();
+			echo $got;
+			return $got;
 		}
 			protected function renderHeader():void
 			{
@@ -164,35 +183,6 @@
 				<footer class="col">
 					<?= jvbLoadingScreen() ?>
 					<?= TaxonomySelector::outputSelectorModal() ?>
-		<!--            <nav class="dashboard-nav">-->
-						<?php
-		//                $current_page = $this->getCurrentPageSlug();
-		//                $pages = $this->getUserAllowedPages()?:[];
-		//                echo '<ul>';
-		//                foreach ($pages as $slug => $page) {
-		//					$slug = $this->getSlug($slug, $page);
-		//					$icon = $this->getIcon($slug, $page);
-		//					// Add data-page attribute for the navigator
-		//                    $active = ($current_page == $slug) ? ' class="current"' : '';
-		//                    $current = ($current_page == $slug) ? ' aria-current="page"' : '';
-		//
-		//
-		//					$link = ($page === 'dash') ? '/'.$page : "/dash/$slug";
-		//                    printf(
-		//                        '<li%s><a href="%s"%s data-page="%s" data-dash title="%s">%s<span>%s</span></a></li>',
-		//                        $active,
-		//                        get_home_url(null, $link),
-		//                        $current,
-		//                        $slug,
-		//                        $page,
-		//                        jvbDashIcon($icon, ['title'=> $page]),
-		//                        $page
-		//                    );
-		//                }
-		//
-		//                echo '</ul>';
-						?>
-		<!--            </nav>-->
 				</footer>
 
 
@@ -210,6 +200,7 @@
 			protected function outputSidebarNavigation():string
 			{
 				$menu = new Navigation('sidebar');
+
 				$menuClasses = ['left'];
 				$itemClasses = ['col'];
 				$menu->addClass('sidebar left')->hasToggle()->defaultMenuClasses($menuClasses);
@@ -219,140 +210,63 @@
 				$dashboard = $menu->addItem('Dashboard', jvbDashIcon($this->pages['dash']->getIcon()))
 					->url($this->pages['dash']->getURL());
 
-				foreach ($this->sections as $section) {
-					$pages = array_filter($this->pages, function($page) use ($section) {
-						$canDo = empty($page->getPermission())  ||  current_user_can($page->getPermission());
-						return $page->getSection() === $section && $canDo;
-					});
+				$all = $this->getSectionPagesAndSections();
 
-					if (empty($pages)) {
-						continue;
-					}
-					$icon = !empty($section['icon']??'') ? jvbDashIcon($section['icon']) : null;
-					$section = $menu->addItem($section['title'], $icon)
-						->submenu($section['slug'])
-						->defaultMenuClasses($menuClasses)
-						->defaultItemClasses($itemClasses);
-					foreach ($pages as $page) {
-						$icon = empty($page->getIcon()) ? null : jvbDashIcon($page->getIcon());
-						$item = $section->addItem($page->getTitle(), $icon)
-							->url($page->getURL());
-						$registrar = Registrar::getInstance($page->getSlug());
-						if ($registrar && !empty($registrar->registrar->taxonomies)) {
-							$itemMenu = $item->submenu($page->getSlug());
-							foreach ($registrar->registrar->taxonomies as $taxonomy) {
-								$taxonomy = jvbNoBase($taxonomy);
-								if (!array_key_exists($taxonomy, $this->pages)) {
-									error_log('Could not add Taxonomy subpage for '.$taxonomy);
-									continue;
-								}
-								$icon = empty($this->pages[$taxonomy]->getIcon()) ? null : jvbDashIcon($this->pages[$taxonomy]->getIcon());
-								$itemMenu->addItem($this->pages[$taxonomy]->getTitle(),$icon)
-									->url($this->pages[$taxonomy]->getURL());
-							}
-						}
-					}
+				unset($all['dash']);
+//				uasort($pages, fn($a, $b) => $a->getOrder() <=> $b->getOrder());
+				uasort($all, fn($a, $b) => $a->getOrder() <=> $b->getOrder());
 
-				}
-				$pages = $this->getUserAllowedPages()?:[];
-				//Dashboard
-					//Referrals
-				$dashboard = $menu->addItem('Dashboard',jvbDashIcon('door'))
-					->url($this->baseURL);
-		//			->submenu('dashboard')
-		//			->defaultMenuClasses($menuClasses)
-		//			->defaultItemClasses($itemClasses);
-				//notifications
-				if (in_array('Notifications', $pages)) {
-					$menu->addItem('Notifications',jvbDashIcon('bell'))
-						->url($this->baseURL.'/notifications');
-				}
-				if (in_array('Referrals', $pages)) {
-					$menu->addItem('Referrals', jvbDashIcon('hand-heart'))
-						->url($this->baseURL.'/referrals');
-				}
-				if (in_array('Favourites', $pages)) {
-					$menu->addItem('Favourites', jvbDashIcon('heart'))
-						->url($this->baseURL.'/favourites');
-				}
-
-				//Content
-					//content types
-				$all = array_merge(
-					Registrar::getRegistered('post'),
-					Registrar::withFeature('is_content', 'term')
-				);
-				$availableContent = [];
-//				$availableContent = array_filter($pages, function($page, $key) use($all) {
-//					return !is_numeric($key) && in_array($key, $all) && JVB()->roles()->checkRole($this->user, $key);
-//				}, ARRAY_FILTER_USE_BOTH);
-				if (!empty ($availableContent)){
-					$content = $menu->addItem('Your Content', jvbDashIcon('book-bookmark'))
-						->submenu('content')
-						->defaultMenuClasses($menuClasses)
-						->defaultItemClasses($itemClasses);
-					foreach ($availableContent as $slug => $page) {
-						$registrar = Registrar::getInstance($slug);
-
-						$item = $content->addItem($page, $registrar->getIcon())
-							->url($this->baseURL.'/'.$slug);
-
-						if ($registrar->getType() === 'post') {
-							$taxonomies = $registrar->registrar->taxonomies;
-							if (!empty ($taxonomies)) {
-								//TODO: If we add a dedicated 'create item' page, remove this from the empty check
-								$itemMenu = $item->submenu($slug);
-								foreach ($taxonomies as $s) {
-									$taxRegistrar = Registrar::getInstance($s);
-									if ($taxRegistrar) {
-										$itemMenu->addItem($taxRegistrar->getPlural(), $taxRegistrar->getIcon())
-										->url($this->baseURL.'/'.$s);
-									}
-
-								}
-							}
-						}
-
-
+				foreach ($all as $slug => $item) {
+					if (is_a($item, Section::class)) {
+						$this->buildMenuSection($item, $menu);
+					} else {
+						$menuItem = $menu->addItem($item->getTitle(), jvbDashIcon($item->getIcon()));
+						$menuItem->url($item->getURL());
 					}
 				}
-
-				//Taxonomies
-
-				//Settings
-				$settings = $menu->addItem('Settings', jvbDashIcon('faders'))
-					->submenu('settings')
-					->defaultItemClasses($itemClasses)
-					->defaultMenuClasses($menuClasses);
-
-					//SEO
-					if (in_array('SEO', $pages)) {
-						$settings->addItem('SEO', jvbDashIcon('robot'))
-							->url($this->baseURL.'/seo');
-					}
-					//Integrations
-					if (in_array('Integrations', $pages)) {
-						$settings->addItem('Integrations', jvbDashIcon('plugs-connected'))
-							->url($this->baseURL.'/integrations');
-					}
-				//Account
-				$account = $menu->addItem('Account', jvbDashIcon('user-circle'))
-					->url($this->baseURL.'/account')
-					->submenu('account')
-					->defaultMenuClasses($menuClasses)
-					->defaultItemClasses($itemClasses);
-				$account->addItem('Reset Password', jvbDashIcon('password'))
-					->url($this->baseURL.'/reset-password');
-					//name + contact
-					//reset password
-
-					if (in_array('notifications', $pages)) {
-						$account->addItem('Permissions', jvbDashIcon('keyhole'))
-							->url($this->baseURL.'/permissions');
-					}
-
-				echo $menu->render();
+				return $menu->render();
 			}
+				protected function buildMenuSection(Section $section, Navigation $menu, array $pages = []):void
+				{
+					$all = $this->getSectionPagesAndSections($section->getSlug());
+					if (empty($all)) {
+						return;
+					}
+					uasort($all, fn($a, $b) => $a->getOrder() <=> $b->getOrder());
+
+					$page = $menu->addItem($section->getTitle(), jvbDashIcon($section->getIcon()));
+
+					$main = $this->getMainPage($section->getSlug());
+					if ($main && $section->getIsLink()) {
+						$page->url($main->getURL());
+					}
+					$submenu = $page->submenu();
+
+					foreach ($all as $slug=>$item) {
+						if (is_a($item, Section::class)) {
+							$this->buildMenuSection($item, $submenu);
+						} elseif ($slug !== $section->getSlug()) {
+							$menuItem = $submenu->addItem($item->getTitle(), jvbDashIcon($item->getIcon()));
+							$menuItem->url($item->getURL());
+						}
+					}
+
+				}
+
+				protected function getSectionPagesAndSections(?string $section = null):array
+				{
+					$pages = $this->getSectionPages($section);
+					$pages = array_filter($pages, function ($p) {
+						return empty($p->getPermission()) || current_user_can('manage_options') || current_user_can($p->getPermission());
+					});
+					$sections = $this->getSectionSections($section);
+					$sections = array_filter($sections, function ($s) {
+						$check = empty($s->getPermission()) || current_user_can('manage_options') || current_user_can($s->getPermission());
+						$pages = $this->getSectionPagesAndSections($s->getSlug());
+						return $check && !empty($pages);
+					});
+					return array_merge($pages, $sections);
+				}
 		public function redirectFromAdmin():void
 		{
 			//Skip if already processing a redirect
@@ -370,7 +284,21 @@
 		}
 		public function dashboardScripts():void
 		{
+			if (!is_singular(self::$based) && !is_post_type_archive(self::$based)) {
+				return;
+			}
+			IconsManager::for('forms')->enqueueIconStyles();
+			IconsManager::for('dash')->enqueueIconStyles();
 
+			wp_enqueue_script('jvb-form');
+			wp_enqueue_script('jvb-selector');
+			wp_enqueue_script('jvb-uploader');
+			wp_enqueue_script('jvb-content');
+
+			$page = $this->getCurrentPage();
+			foreach ($page->getScripts() as $script) {
+				wp_enqueue_script($script);
+			}
 		}
 
 		public function excludeDashboard(array $IDs):array {
@@ -378,7 +306,7 @@
 				'dashboardIDs',
 				function() {
 					return get_posts([
-						'post_type'	=> BASE.'dash',
+						'post_type'	=> self::$based,
 						'posts_per_page' => -1,
 						'fields' => 'ids',
 					]);
@@ -392,110 +320,182 @@
 
 	private function buildPages():void
 	{
-		$this->addPage('dash', 'Dashboard','door');
-		$this->buildContentPages();
-		$this->buildReferrals();
+		$this->addPage('Dashboard', 'dash','door');
+		$this->buildContentPages(10);
+		$this->buildReferrals(30);
+		$this->buildFavourites(5);
+		$this->buildKarma(15);
+		$this->buildNotifications(20);
 		$this->buildMembership();
-		$this->buildFavourites();
-		$this->buildKarma();
-		$this->buildNotifications();
-		$this->buildIntegrations();
-		$this->buildSettingsPages();
-		$this->buildAccountPages();
+		$this->buildIntegrations(35);
+		$this->buildSettingsPages(40);
+		$this->buildAccountPages(50);
 	}
 
-		private function buildContentPages():void
+		private function buildContentPages(int $order = 10):void
 		{
 			$content = Registrar::getRegistered('post');
+			$this->sections['content'] = new Section('Your Content', 'content', 'book-bookmark');
+			$this->sections['content']->setOrder($order);
 			foreach ($content as $c) {
 				$registrar = Registrar::getInstance($c);
 				$page = $this->addPage($registrar->getPlural(), $c, $registrar->getIcon());
 				$page->setPermission(RoleManager::getPermissionName('edit', $c));
 				$page->setSection('content');
+				$page->setScripts(['jvb-crud', 'jvb-creator']);
+				$this->sections[$c] = new Section($registrar->getPlural(), $c, $registrar->getIcon(), 'content');
+				$this->sections[$c]->setPermission(RoleManager::getPermissionName('edit', $c));
+				$this->sections[$c]->setIsLink(true);
+
+				$taxonomies = $registrar->registrar->taxonomies;
+				foreach ($taxonomies as $tax) {
+					$taxReg = Registrar::getInstance($tax);
+					if ($taxReg) {
+						$taxPage = $this->addPage($taxReg->getPlural(), $tax, $registrar->getIcon(), $page->getID());
+						$taxPage->setPermission(RoleManager::getPermissionName('edit', $c));
+						$taxPage->setSection($c);
+
+						$taxPage->setScripts(['jvb-crud', 'jvb-creator']);
+					}
+				}
 				$this->pages[$c] = $page;
 			}
+
+			$contentTax = Registrar::withFeature('is_content', 'term');
+			foreach ($contentTax as $c) {
+				$registrar = Registrar::getInstance($c);
+				$page = $this->addPage($registrar->getPlural(), $c, $registrar->getIcon());
+				$page->setPermission(RoleManager::getPermissionName('edit', $c));
+				$page->setSection($c);
+				//TODO: add artist management and invitations, if applicable
+			}
 		}
 
-		private function buildSettingsPages():void
+		private function buildSettingsPages(int $order = 40):void
 		{
+			$this->sections['settings'] = new Section('Settings', 'settings', 'gear-six');
+			$this->sections['settings']->setOrder($order);
+
 			$seo = $this->addPage('SEO', 'seo', 'robot');
 			$seo->setSection('settings');
 			$seo->setPermission('manage_options');
+			$seo->setScripts(['jvb-schema']);
+			//TODO: Create permission that user has editable content
 			$this->pages['seo'] = $seo;
 
 		}
-		private function buildAccountPages():void
+		private function buildAccountPages(int $order = 50):void
 		{
 			if (Site::has('support')) {
+				$this->sections['support'] = new Section('Support', 'support', 'question');
+				$this->sections['support']->setOrder($order + 5);
 				$page = $this->addPage('Support', 'support', 'question');
 				$page->setSection('support');
 			}
 
 			$account = $this->addPage('Account', 'account', 'user-circle');
 			$account->setSection('account');
-			$accountID = $account->getID();
 
-			$password = $this->addPage('Reset Password', 'reset-password', 'password', $accountID);
+			$this->sections['account'] = new Section('Account', 'account', 'user-circle');
+			$this->sections['account']->setOrder($order);
+			$this->sections['account']->setIsLink(true);
+
+
+			$password = $this->addPage('Reset Password', 'reset-password', 'password', $account->getID());
 			$password->setOrder(2);
 			$password->setSection('account');
 
 		}
-		private function buildReferrals():void
+		private function buildReferrals(int $order = 30):void
 		{
 			if (Site::has('referrals')) {
 				$page = $this->addPage('Referrals', 'referrals', 'hand-heart');
+				$page->setOrder($order);
 			}
 		}
 		private function buildMembership():void
 		{
 			$membership = Site::membership();
 			if ($membership) {
+				$buildNotification = false;
 				if ($membership->has('can_invite')) {
+					$buildNotification = true;
 					$page = $this->addPage('Invite', 'invite', '');
 					$page->setSection('notifications');
 				}
 				if ($membership->has('term_approval')) {
+					$buildNotification = true;
 					$page = $this->addPage('Approvals', 'approvals', 'check-circle');
 					$page->setSection('notifications');
 				}
 				if ($membership->has('forum')) {
 					$page = $this->addPage('Forum', 'forum', 'chats-teardrop');
+					$page->setScripts(['jvb-news']);
 				}
 				if ($membership->has('member_content')) {
 					$page = $this->addPage('Metrics', 'metrics', 'chart-line');
 				}
+
+				if ($buildNotification){
+					$this->buildNotificationSection();
+				}
 			}
 		}
-		private function buildFavourites():void
+		private function buildFavourites(int $order = 5):void
 		{
 			if (Site::has('favourites')) {
+				$this->sections['favourites'] = new Section('Favourites', 'favourites', 'heart');
+				$this->sections['favourites']->setOrder($order);
 				$page = $this->addPage('Favourites', 'favourites', 'heart');
-				//TODO: Lists, Share permissions
+				$page->setSection('favourites');
+				$page->setScripts(['jvb-favourites']);
+
+				$lists = $this->addPage('Lists', 'lists', 'list-heart', $page->getID());
+				$lists->setSection('favourites');
+				$lists->setScripts(['jvb-favourites']);
+
+				$permissions = $this->addPage('Permissions', 'permissions', 'hand-heart', $page->getID());
+				$permissions->setSection('favourites');
+				$permissions->setScripts(['jvb-favourites']);
 			}
 		}
-		private function buildKarma():void
+		private function buildKarma(int $order = 15):void
 		{
 			if (!empty(Registrar::withFeature('karma'))) {
 				$page = $this->addPage('Karmic', 'karmic', 'arrow-fat-up');
+				$page->setOrder($order);
 			}
 		}
-		private function buildNotifications():void
+		private function buildNotifications(int $order = 20):void
 		{
 			if (Site::has('notifications')) {
+				$this->buildNotificationSection($order);
 				$page = $this->addPage('Notifications', 'notifications', 'bell');
 				$page->setSection('notifications');
+				$page->setScripts(['jvb-notifications-manager']);
 
 				$page = $this->addPage('Permissions', 'permissions', 'gear-six');
 				$page->setSection('notifications');
-				$page->setOrder(999);
 			}
 		}
-		private function buildIntegrations():void
+			private function buildNotificationSection(int $order = 20):void
+			{
+				$this->sections['notifications'] = new Section('Notifications', 'notifications', 'bell');
+				$this->sections['notifications']->setOrder($order);
+			}
+		private function buildIntegrations(int $order = 35):void
 		{
 			if (Site::hasAnyIntegration()) {
 				$page = $this->addPage('Integrations', 'integrations', 'plugs-connected');
 				$page->setSection('settings');
+				$page->setOrder($order);
+				$page->setScripts(['jvb-integrations']);
 				$parent = $page->getID();
+
+				$this->sections['integrations'] = new Section('Integrations', 'integrations', 'plugs-connected', 'settings');
+				$this->sections['integrations']->setOrder($order);
+				$this->sections['integrations']->setIsLink(true);
+
 				foreach (array_keys(Site::getIntegrations()) as $integration) {
 					$integration = match($integration) {
 						'maps' => 'JVBase\integrations\GoogleMaps',
@@ -511,7 +511,13 @@
 					};
 					$title = $integration::title();
 					$icon = $integration::icon();
-					$page = $this->addPage($title, $title, $icon, $parent);
+					if ($integration::hasExtraOptions()) {
+						$page = $this->addPage($title, $title, $icon, $parent);
+
+						$page->setScripts(['jvb-integrations']);
+						$page->setSection('integrations');
+					}
+
 				}
 			}
 		}
@@ -519,7 +525,7 @@
 	public function addPage(string $title, string $slug = '', string $icon = '', int $parent = 0):DashboardPage
 	{
 		$page = new DashboardPage($title, $slug, $icon, $parent);
-		$this->pages[$page->getSlug()] = $page;
+		$this->pages[$slug] = $page;
 		return $page;
 	}
 
@@ -528,71 +534,46 @@
 		$sections = array_values(array_filter(array_unique(array_map(function ($page) {
 			return $page->getSection();
 		}, $this->pages))));
-		foreach ($sections as $section) {
-			$isLink = false;
-			switch ($section) {
-				case 'content':
-					$title = 'Your Content';
-					$icon = 'book-bookmark';
-					break;
-				case 'settings':
-					$title = 'Settings';
-					$icon = 'faders';
-					break;
-				case 'account':
-					$title = 'Account';
-					$icon = 'user-circle';
-					break;
-				case 'notifications':
-					$title = 'Notifications';
-					$icon = 'bell';
-					break;
-				case 'support':
-					$title = 'Support';
-					$icon = 'question';
-					break;
-				default:
-					$mainPage = $this->getMainPage($section);
-					if ($mainPage) {
-						$title = $mainPage->getTitle();
-						$icon = $mainPage->getIcon();
-						$isLink = true;
-					} else {
-						error_log('[DashboardManager]::buildSections Could not create section for '.$section);
-						return;
-					}
-					break;
-			}
-
-			if (!$isLink && $this->hasMainPage($section)) {
-				$isLink = true;
-			}
-
-			$this->sections[$section] = new Section($title, $section, $icon);
-			if ($isLink) {
-				$this->sections[$section]->setIsLink(true);
-			}
+		$missing = array_diff($sections, array_map(function($s) { return $s->getSlug(); }, $this->sections));
+		if (!empty($missing)) {
+			error_log('[DashboardManager]::buildSections Section mentioned, but not defined: '.print_r($missing, true));
 		}
+
+//		foreach ($sections as $section) {
+//			$isLink = $this->hasMainPage($section);
+//			if ($isLink) {
+//				$this->sections[$section]->setIsLink(true);
+//			}
+//		}
 	}
-		protected function getSectionPages(string $section):array
+		protected function getSectionPages(?string $section = null):array
 		{
 			return array_filter($this->pages, function($page) use ($section) {
 				return $page->getSection() === $section;
 			});
 		}
+		protected function getSectionSections(?string $section = null):array
+		{
+			return array_filter($this->sections, function($s) use ($section) {
+				return $s->getParent() === $section;
+			});
+		}
 
 		protected function getMainPage(string $section):DashboardPage|false
 		{
-			$sectionPages = $this->getSectionPages($section);
-			$mainPage = array_filter($sectionPages, function ($page) use ($section) {
+
+			$section = DashboardPage::sanitizeString($section);
+
+			$mainPage = array_values(array_filter($this->pages, function ($page) use ($section) {
 				return $page->getSlug() === $section;
-			});
+			}));
 
 			return empty($mainPage) ? false : $mainPage[0];
 		}
 
 		protected function hasMainPage(string $section):bool
 		{
+			$section = DashboardPage::sanitizeString($section);
 			return $this->getMainPage($section) !== false;
 		}
 
@@ -615,16 +596,22 @@
 		return true;
 	}
 
+	protected function setCurrentUserPages():void
+	{
+		$this->currentUserPages = array_filter($this->pages, function($page) {
+			return current_user_can('manage_options') || empty($page->getPermission()) || current_user_can($page->getPermission());
+		});
+	}
 
 	#[NoReturn]protected function redirectToLogin():void
 	{
-		wp_redirect(wp_login_url(get_home_url(null, '/dash')));
+		wp_redirect(wp_login_url(get_home_url(null, '/'.$this->slug)));
 		exit;
 	}
 
 	#[NoReturn]protected function redirectToDashboard():void
 	{
-		wp_redirect(get_home_url(null, '/dash'));
+		wp_redirect(get_home_url(null, '/'.$this->slug));
 		exit;
 	}
 	#[NoReturn]protected function redirectToHome():void
@@ -636,16 +623,19 @@
 	protected function getCurrentPage():DashboardPage|false
 	{
 		$slug = $this->getCurrentPageSlug();
-		if (!array_key_exists($slug, $this->pages)) {
+		$page = array_filter($this->pages, function($p) use ($slug) {
+			return $p->getSlug() === $slug;
+		});
+		if (empty($page)) {
 			error_log('[DashboardManager]::getCurrentPage Could not get configuration for '.$slug);
 			return false;
 		}
-		return $this->pages[$slug];
+		return $page[array_key_first($page)];
 	}
 
 	protected function getCurrentPageSlug():string
 	{
-		if (is_post_type_archive(BASE.'dash')) {
+		if (is_post_type_archive(self::$based)) {
 			return 'dash';
 		}
 
@@ -656,4 +646,49 @@
 
 		return $post->post_name;
 	}
+
+
+	public function renderMain(string $slug):void
+	{
+		if ($slug !== 'dash') {
+			return;
+		}
+		$user = get_userdata(get_current_user_id());
+		$name = ($user->first_name !== '') ? $user->first_name : $user->display_name;
+
+		echo sprintf(
+			'<h1>Hey %s</h1><p>Welcome back!</p>',
+			$name
+		);
+
+		$reg = Registrar::getInstance(jvbUserRole($user->ID));
+		if ($reg && !empty($reg->getCreatable())) {
+			echo '<p>Everything saves auto-magically - so rest easy.</p>';
+		}
+	}
+
+	public function renderAccount():void
+	{
+
+		$user = get_userdata(get_current_user_id());
+		$role = jvbUserRole($user->ID);
+		$registrar = Registrar::getInstance($role);
+
+
+		if ($registrar) {
+			$meta = Meta::forUser($user->ID);
+			$fields = $registrar->getFields();
+		} else {
+			$fields = Fields::getUserFields();
+			$meta = new Meta($user->ID, 'user', $fields);
+		}
+
+		echo Form::renderFormFrom($meta, 'user', [
+			'heading'	=> 'Your Account',
+			'description' => [
+				'You can set your information here.',
+				'To reset your password, check the side menu under "Account"'
+			]
+		]);
+	}
 }

--
Gitblit v1.10.0