type = $type; $this->links = $this->getNavigationLinks($type); } public function render() { return view('navbar-manager::components.navigation-links'); } private function getNavigationLinks($type) { try { $links = NavbarLink::where('type', $type) ->where('is_active', true) ->whereNull('parent_id') ->orderBy('sort_order') ->with('children') ->get(); $navLinks = []; foreach ($links as $link) { if ($this->shouldShowLink($link)) { $formattedLink = $this->formatLink($link); if ($formattedLink) { $navLinks[] = $formattedLink; } } } return $navLinks; } catch (\Exception $e) { \Log::error('NavbarManager: Error loading navigation links', [ 'type' => $type, 'error' => $e->getMessage() ]); return []; } } private function shouldShowLink($link) { try { switch ($link->condition) { case 'always_visible': return true; case 'always_hidden': return false; case 'clients_only': return auth()->check() && auth()->user()->role === null; case 'admin_only': return auth()->check() && auth()->user()->role !== null; case 'guests_only': return !auth()->check(); default: return true; } } catch (\Exception $e) { return true; } } private function formatLink($link) { try { $formatted = [ 'name' => $link->name, 'priority' => $link->sort_order, ]; // Add icon with validation and strip -line/-fill suffix if ($link->icon && $this->isValidIcon($link->icon)) { // Remove -line or -fill suffix since Navigation::markActiveRoute will add it $baseIcon = preg_replace('/-(?:line|fill)$/', '', $link->icon); $formatted['icon'] = $baseIcon; } // Handle different link types switch ($link->link_type) { case 'route': if ($link->route_name) { $formatted['route'] = $link->route_name; $formatted['spa'] = true; // Enable SPA for route links if ($link->route_params) { // Get raw attribute to avoid accessor transformation $rawParams = $link->getAttributes()['route_params'] ?? null; $params = is_string($rawParams) ? json_decode($rawParams, true) : $rawParams; if ($params && is_array($params)) { $formatted['params'] = $params; } } } else { return null; } break; case 'path': case 'url': // Use navbar redirect route $formatted['route'] = 'navbar.redirect'; $formatted['params'] = ['linkId' => $link->id]; $formatted['spa'] = false; // Disable SPA for external links break; case 'product': if ($link->product_id) { try { $product = \App\Models\Product::with('category')->find($link->product_id); if ($product && $product->category) { $formatted['route'] = 'products.show'; $formatted['params'] = [ 'category' => $product->category->slug ?? $product->category->id, 'product' => $product->slug ?? $product->id ]; $formatted['spa'] = true; } else { return null; } } catch (\Exception $e) { return null; } } else { return null; } break; case 'category': if ($link->category_id) { try { $category = \App\Models\Category::find($link->category_id); if ($category) { $formatted['route'] = 'category.show'; $formatted['params'] = ['category' => $category->slug ?? $category->id]; $formatted['spa'] = true; } else { return null; } } catch (\Exception $e) { return null; } } else { return null; } break; } // Handle children (dropdown items) if ($link->children && $link->children->count() > 0) { $children = []; foreach ($link->children->where('is_active', true) as $child) { if ($this->shouldShowLink($child)) { $childFormatted = $this->formatLink($child); if ($childFormatted) { $children[] = $childFormatted; } } } if (!empty($children)) { $formatted['children'] = $children; } } return $formatted; } catch (\Exception $e) { \Log::error('NavbarManager: Error formatting link', [ 'link_id' => $link->id ?? 'unknown', 'error' => $e->getMessage() ]); return null; } } private function isValidIcon($icon) { // Basic validation for RemixIcon format if (!preg_match('/^ri-[\w-]+$/', $icon)) { return false; } return true; } }