Files

384 lines
21 KiB
PHP

<div class="adminuiux-wrap">
{{-- Standard sidebar --}}
<div class="adminuiux-sidebar shadow-sm">
<div class="adminuiux-sidebar-inner">
<ul class="nav flex-column menu-active-line mt-3">
{{-- INSTANCE MODE --}}
<li id="sidebar-mode-container"
class="nav-item px-3 mb-2 mt-2 {{ ($instance_mode ?? 'Production') === 'Production' ? 'd-none' : '' }}">
@php
$modeClass = match ($instance_mode ?? 'Production') {
'Demo' => 'bg-info text-dark',
'Trial' => 'bg-warning text-dark',
default => 'bg-success text-white'
};
@endphp
<div id="sidebar-mode-badge"
class="badge {{ $modeClass }} w-100 py-2 rounded-pill fw-bold shadow-sm d-flex align-items-center justify-content-center"
style="letter-spacing: 0.5px;">
<i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; opacity: 0.8;"></i>
<span id="sidebar-mode-text">{{ strtoupper($instance_mode ?? 'Production') }}</span>
</div>
</li>
{{-- GROUP: OVERVIEW --}}
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-3"
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('OVERVIEW') }}</li>
{{-- DASHBOARD --}}
@can('view dashboard')
<li class="nav-item">
<a href="{{ route('dashboard') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('dashboard') ? 'active' : '' }}">
<i class="menu-icon bi bi-cpu me-2"></i>
<span class="menu-name">Dashboard</span>
</a>
</li>
@endcan
{{-- NOTIFICATION CENTER --}}
@php
$isNotificationEnabled = get_setting('feature_notification_center', true);
$canManageSettings = Auth::user()?->can('manage global settings');
$canViewNotifications = Auth::user()?->can('view notification center');
// Show if feature is on OR if user is an admin (who can see it even if disabled)
$showNotificationMenu = ($isNotificationEnabled && $canViewNotifications) || $canManageSettings;
@endphp
@if($showNotificationMenu)
<li class="nav-item">
<a href="{{ route('notification-center.index') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('notification-center*') ? 'active' : '' }}">
<i class="menu-icon bi bi-bell me-2"></i>
<span class="menu-name">Notification</span>
</a>
</li>
@endif
{{-- GROUP: ACCESS --}}
@canany(['view user directory', 'view access rights', 'view active sessions'])
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('ACCESS') }}</li>
@php
$isUserSecurityActive = request()->routeIs('users*') || request()->routeIs('roles*') || request()->routeIs('session-manager*');
@endphp
<li class="nav-item">
<button type="button"
id="btn-user-security-toggle"
class="nav-link d-flex align-items-center w-100 border-0 bg-transparent text-start"
data-sidebar-toggle="userSecuritySubmenu"
aria-expanded="{{ $isUserSecurityActive ? 'true' : 'false' }}">
<i class="menu-icon bi bi-person-lock me-2"></i>
<span class="menu-name">User &amp; Security</span>
<i class="bi bi-chevron-down ms-auto x-small" id="chevron-user-security"></i>
</button>
<ul class="nav flex-column ps-4 mb-2" id="userSecuritySubmenu"
style="{{ $isUserSecurityActive ? '' : 'display:none;' }}overflow:hidden;transition:all 0.2s ease;">
@can('view user directory')
<li class="nav-item">
<a href="{{ route('users') }}"
class="nav-link py-1 {{ request()->routeIs('users*') ? 'active' : '' }}">
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
<span class="menu-name small">User Directory</span>
</a>
</li>
@endcan
@can('view access rights')
<li class="nav-item">
<a href="{{ route('roles') }}"
class="nav-link py-1 {{ request()->routeIs('roles*') || request()->routeIs('permissions*') ? 'active' : '' }}">
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
<span class="menu-name small">Access Rights</span>
</a>
</li>
@endcan
@can('view active sessions')
<li class="nav-item">
<a href="{{ route('session-manager') }}"
class="nav-link py-1 {{ request()->routeIs('session-manager*') ? 'active' : '' }}">
<i class="bi bi-circle me-2 small" style="font-size: 0.5rem;"></i>
<span class="menu-name small">Active Sessions</span>
</a>
</li>
@endcan
</ul>
</li>
@endcanany
{{-- GROUP: MONITORING --}}
@canany(['view health and logs', 'view action history'])
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('MONITORING') }}</li>
{{-- MONITORING --}}
@can('view health and logs')
<li class="nav-item">
<a href="{{ route('system-monitoring') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('system-monitoring') ? 'active' : '' }}">
<i class="menu-icon bi bi-speedometer2 me-2"></i>
<span class="menu-name">Health & Logs</span>
</a>
</li>
@endcan
{{-- ACTION LOGS --}}
@can('view action history')
<li class="nav-item">
<a href="{{ route('action-logs') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('action-logs*') ? 'active' : '' }}">
<i class="menu-icon bi bi-journal-text me-2"></i>
<span class="menu-name">Action History</span>
</a>
</li>
@endcan
@endcanany
{{-- GROUP: CONFIGURATION --}}
@canany(['view backup and storage', 'view maintenance mode', 'view global settings', 'view mobile settings'])
<li class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4"
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('CONFIGURATION') }}</li>
@can('view backup and storage')
<li class="nav-item">
<a href="{{ route('backup-restore.index') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('backup-restore.*') ? 'active' : '' }}">
<i class="menu-icon bi bi-database-check me-2"></i>
<span class="menu-name">Backup & Storage</span>
</a>
</li>
@endcan
@can('view maintenance mode')
<li class="nav-item">
<a href="{{ route('maintenance-mode') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('maintenance-mode') ? 'active' : '' }}">
<i class="menu-icon bi bi-exclamation-octagon me-2"></i>
<span class="menu-name">Maintenance</span>
</a>
</li>
@endcan
@can('view global settings')
<li class="nav-item">
<a href="{{ route('system-config') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('system-config') && !request()->has('anchor') ? 'active' : '' }}">
<i class="menu-icon bi bi-sliders me-2"></i>
<span class="menu-name">Global Settings</span>
</a>
</li>
@endcan
@can('view mobile settings')
<li class="nav-item">
<a href="{{ route('mobile-settings.index') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('mobile-settings*') ? 'active' : '' }}">
<i class="menu-icon bi bi-phone-vibrate me-2"></i>
<span class="menu-name">Mobile Settings</span>
</a>
</li>
@endcan
@endcanany
{{-- GROUP: DEVELOPER --}}
@canany(['view pulse', 'view telescope', 'view api docs'])
@php
$pulseEnabled = (bool) get_setting('engine_pulse_enabled', true);
$telescopeEnabled = (bool) get_setting('engine_telescope_enabled', true);
$swaggerEnabled = (bool) get_setting('engine_swagger_enabled', true);
$horizonEnabled = (bool) get_setting('engine_horizon_enabled', true);
$aiDiagEnabled = Auth::user()?->can('view ai self-healing')
? (bool) get_setting('ai_healing_enabled', false)
: false;
$showDevGroup = $pulseEnabled || $telescopeEnabled || $swaggerEnabled || $horizonEnabled || $aiDiagEnabled;
@endphp
<li id="sidebar-dev-group"
class="nav-label text-uppercase text-secondary small fw-bold px-4 mb-2 mt-4 {{ !$showDevGroup ? 'd-none' : '' }}"
style="letter-spacing: 1px; opacity: 0.6; font-size: 0.7rem;">{{ __('DEVELOPER') }}</li>
{{-- 0. AI DIAGNOSTICS --}}
@can('view ai self-healing')
<li id="menu-ai-diagnostics" class="nav-item {{ !$aiDiagEnabled ? 'd-none' : '' }}"
x-data="{ pending: 0 }" x-init="
const _fetchAiStats = () => fetch('{{ route('ai-self-healing.stats') }}').then(r=>r.json()).then(d=>{ pending = d.pending||0; }).catch(()=>{});
_fetchAiStats();
setInterval(_fetchAiStats, 30000);
">
<a href="{{ route('ai-self-healing.index') }}"
class="nav-link d-flex align-items-center {{ request()->routeIs('ai-self-healing.*') ? 'active' : '' }}">
<i class="menu-icon bi bi-robot me-2 text-danger"></i>
<span class="menu-name">AI Diagnostics</span>
<span x-show="pending > 0" x-text="pending > 9 ? '9+' : pending"
class="badge bg-warning text-dark ms-auto rounded-pill"
style="font-size:.6rem;min-width:18px;padding:2px 5px;" x-cloak></span>
</a>
</li>
@endcan
{{-- 1. HORIZON QUEUE MONITOR --}}
@can('manage global settings')
<li id="menu-horizon" class="nav-item {{ !$horizonEnabled ? 'd-none' : '' }}">
<a href="/horizon" target="_blank" class="nav-link d-flex align-items-center">
<i class="menu-icon bi bi-speedometer2 me-2 text-primary"></i>
<span class="menu-name">Horizon</span>
</a>
</li>
@endcan
{{-- 2. PULSE MONITORING --}}
@can('view pulse')
<li id="menu-pulse" class="nav-item {{ !$pulseEnabled ? 'd-none' : '' }}">
<a href="/pulse" target="_blank" class="nav-link d-flex align-items-center">
<i class="menu-icon bi bi-activity me-2 text-info"></i>
<span class="menu-name">Pulse</span>
</a>
</li>
@endcan
{{-- 3. TELESCOPE DEBUGGER --}}
@can('view telescope')
<li id="menu-telescope" class="nav-item {{ !$telescopeEnabled ? 'd-none' : '' }}">
<a href="/telescope" target="_blank" class="nav-link d-flex align-items-center">
<i class="menu-icon bi bi-bug me-2 text-warning"></i>
<span class="menu-name">Telescope</span>
</a>
</li>
@endcan
{{-- 4. API DOCUMENTATION --}}
@can('view api docs')
<li id="menu-swagger" class="nav-item {{ !$swaggerEnabled ? 'd-none' : '' }}">
<a href="/api/documentation" target="_blank" class="nav-link d-flex align-items-center">
<i class="menu-icon bi bi-code-square me-2 text-success"></i>
<span class="menu-name">API Doc</span>
</a>
</li>
@endcan
@endcanany
<hr class="mx-3 opacity-10">
{{-- LOGOUT --}}
<li class="nav-item">
<a href="javascript:void(0)" class="nav-link d-flex align-items-center text-danger"
onclick="confirmLogout();">
<i class="menu-icon bi bi-box-arrow-right me-2"></i>
<span class="menu-name">Logout Session</span>
</a>
</li>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
@csrf
</form>
<script>
function confirmLogout() {
StandardSwal.fire({
title: 'Confirm Logout',
text: 'Are you sure you want to log out from your session?',
icon: 'warning',
showCancelButton: true,
customClass: {
confirmButton: 'btn-pill-danger',
cancelButton: 'btn-pill-cancel'
},
confirmButtonText: 'Yes, Logout',
cancelButtonText: 'Cancel',
}).then((result) => {
if (result.isConfirmed) {
document.getElementById('logout-form').submit();
}
});
}
</script>
</ul>
<div class=" mt-auto "></div>
<div class="container mt-3 mt-lg-4" id="main-content" style="margin-top: 0rem !important;">
<div class="row gx-3 align-items-center ms-4">
<div class="col mb-3 mb-lg-4">
<div class="row gx-2 align-items-center">
<div class="col-auto col-md-auto text-center">
<a href="{{ route('profile.edit') }}" class="style-none position-relative d-block">
<figure class="avatar avatar-50 rounded coverimg align-middle">
<img src="{{ asset('assets/img/profile.png') }}" alt="">
</figure>
</a>
</div>
<div class="col">
<h5 class="fw-medium mb-0">Hello,</h5>
<h3><span class="text-theme-1">{{ Auth::user()->name ?? 'User' }}</span></h3>
</div>
<div class="col-auto text-end mb-3 mb-lg-4">
<a href="mobileux-wallet-sendmoney.html" class="style-none">
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{-- adminuiux-wrap closed in app.blade.php after <main> so that .adminuiux-content sits inside the wrap --}}
<script>
(function () {
'use strict';
function initSidebarSubmenus() {
var buttons = document.querySelectorAll('[data-sidebar-toggle]');
buttons.forEach(function (btn) {
// Remove any existing listeners to prevent duplicates
var newBtn = btn.cloneNode(true);
btn.parentNode.replaceChild(newBtn, btn);
newBtn.addEventListener('click', function (e) {
e.stopPropagation();
var targetId = this.getAttribute('data-sidebar-toggle');
var submenu = document.getElementById(targetId);
var chevron = this.querySelector('.bi-chevron-down');
if (!submenu) return;
var isOpen = submenu.style.display !== 'none';
if (isOpen) {
submenu.style.display = 'none';
this.setAttribute('aria-expanded', 'false');
if (chevron) chevron.style.transform = 'rotate(0deg)';
} else {
submenu.style.display = 'block';
this.setAttribute('aria-expanded', 'true');
if (chevron) chevron.style.transform = 'rotate(180deg)';
}
});
// Set initial chevron state based on current aria-expanded
var chevron = newBtn.querySelector('.bi-chevron-down');
if (chevron) {
var expanded = newBtn.getAttribute('aria-expanded') === 'true';
chevron.style.transform = expanded ? 'rotate(180deg)' : 'rotate(0deg)';
chevron.style.transition = 'transform 0.2s ease';
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSidebarSubmenus);
} else {
initSidebarSubmenus();
}
})();
</script>