@props(['active' => 'overview']) @php $supportOpen = $supportUnassigned = 0; try { $supportOpen = (int) \App\Models\SupportTicket::whereIn('status', ['open', 'in_progress', 'pending'])->count(); $supportUnassigned = (int) \App\Models\SupportTicket::whereNull('assigned_agent_id') ->whereIn('status', ['open', 'pending']) ->count(); } catch (\Throwable $e) { } // Live counts for the rest of the sidebar — every "static" 4 / 142 // / 18k / 1.2k pill was hard-coded prototype text. These now read // from the actual tables. Each is wrapped so a missing table / // schema mismatch never takes the sidebar down. $fmtCount = function (int $n): string { if ($n >= 1000000) { return number_format($n / 1000000, $n >= 10000000 ? 0 : 1) . 'M'; } if ($n >= 1000) { return number_format($n / 1000, $n >= 10000 ? 0 : 1) . 'k'; } return (string) $n; }; $usersCount = $rolesCount = $permsCount = $workspacesCount = 0; $packagesCount = $creditPackagesCount = $couponsCount = $billingHistoryCount = $orderHistoryCount = $invoicesCount = 0; $supportTeamCount = $supportAgentsCount = $supportSlaCount = $supportCustomersCount = $supportPlaybooksCount = 0; $announcementsCount = $guidebookCount = 0; $contactUnread = 0; try { $contactUnread = (int) \App\Models\ContactMessage::where('is_read', false)->count(); } catch (\Throwable $e) { } try { $usersCount = (int) \App\Models\User::query()->count(); } catch (\Throwable $e) { } try { $rolesCount = (int) \DB::table('roles')->count(); } catch (\Throwable $e) { } try { $permsCount = (int) \DB::table('permissions')->count(); } catch (\Throwable $e) { } try { $workspacesCount = (int) \App\Models\Workspace::query()->count(); } catch (\Throwable $e) { } try { $packagesCount = (int) \App\Models\Package::query()->count(); } catch (\Throwable $e) { } try { $creditPackagesCount = (int) \App\Models\CreditPackage::query()->count(); } catch (\Throwable $e) { } // Coupons badge = active coupons only — expired/disabled coupons // are noise on the sidebar. "active" means is_active + within // valid_from/valid_to window when those columns exist. try { $couponsCount = (int) \App\Models\Coupon::query() ->when(\Schema::hasColumn('coupons', 'is_active'), fn($q) => $q->where('is_active', true)) ->count(); } catch (\Throwable $e) { } try { $billingHistoryCount = (int) \DB::table('orders')->count(); } catch (\Throwable $e) { } try { $orderHistoryCount = (int) \DB::table('orders')->count(); } catch (\Throwable $e) { } try { $invoicesCount = (int) \DB::table('orders')->where('status', 'paid')->count(); } catch (\Throwable $e) { } // Support group children. Each lookup is independent so a missing // table on a fresh install just leaves that badge blank. try { $supportTeamCount = (int) \App\Models\SupportTicket::whereNull('assigned_agent_id') ->whereIn('status', ['open', 'pending', 'in_progress']) ->count(); } catch (\Throwable $e) { } try { $supportAgentsCount = (int) \App\Models\SupportAgent::where('is_active', true)->count(); } catch (\Throwable $e) { } // SLA badge = tickets with first_response/resolution SLA at risk // or already breached. Cheap heuristic: open tickets without a // first_response_at older than the workspace SLA window. Falls // back to all open tickets if the SLA column isn't there. try { $supportSlaCount = (int) \App\Models\SupportTicket::query() ->whereIn('status', ['open', 'pending', 'in_progress']) ->whereNull('first_response_at') ->count(); } catch (\Throwable $e) { } // Customers = distinct visitor emails seen in support tickets — // proxy for "people we've supported" until the explicit // support_customers table is populated. try { $supportCustomersCount = (int) \App\Models\SupportTicket::query() ->whereNotNull('email') ->distinct('email') ->count('email'); } catch (\Throwable $e) { } try { $supportPlaybooksCount = (int) \App\Models\Playbook::where('is_active', true)->count(); } catch (\Throwable $e) { } // Marketing group — only count "live" rows so the badge tells // admins what visitors actually see. try { $announcementsCount = (int) \App\Models\Announcement::query() ->when(\Schema::hasColumn('announcements', 'is_active'), fn($q) => $q->where('is_active', true)) ->count(); } catch (\Throwable $e) { } try { $guidebookCount = (int) \App\Models\GuidebookArticle::query() ->when(\Schema::hasColumn('guidebook_articles', 'is_published'), fn($q) => $q->where('is_published', true)) ->count(); } catch (\Throwable $e) { } $nav = [ [ 'type' => 'leaf', 'key' => 'overview', 'href' => url('/admin'), 'label' => __('Overview'), 'icon' => '', 'sw' => 1.6, ], [ 'type' => 'leaf', 'key' => 'financial', 'href' => url('/admin/financial'), 'label' => __('Financial'), 'icon' => '', 'sw' => 1.6, ], [ 'type' => 'leaf', 'key' => 'premium', 'href' => url('/admin/premium'), 'label' => __('Premium'), 'icon' => '', 'sw' => 1.4, ], [ 'type' => 'leaf', 'key' => 'analytics', 'href' => url('/admin/analytics'), 'label' => __('Analytics'), 'icon' => '', 'sw' => 1.6, ], [ 'type' => 'group', 'key' => 'access', 'label' => __('Users & access'), 'icon' => '', 'sw' => 1.5, 'children' => [ [ 'key' => 'users', 'href' => url('/admin/users'), 'label' => __('Users'), 'badge' => $usersCount > 0 ? $fmtCount($usersCount) : null, ], [ 'key' => 'roles', 'href' => url('/admin/roles'), 'label' => __('Roles'), 'badge' => $rolesCount > 0 ? (string) $rolesCount : null, ], [ 'key' => 'permissions', 'href' => url('/admin/permissions'), 'label' => __('Permissions'), 'badge' => $permsCount > 0 ? (string) $permsCount : null, ], ], ], [ 'type' => 'leaf', 'key' => 'workspaces', 'href' => url('/admin/workspaces'), 'label' => __('Workspaces'), 'icon' => '', 'sw' => 1.6, 'badge' => $workspacesCount > 0 ? $fmtCount($workspacesCount) : null, ], // ───────────────────────────────────────────────────────────── // Commented out — these items already exist on the user side // (top nav + /more page), so the admin console doesn't need to // duplicate them. Restore by un-commenting the block(s) below. // ───────────────────────────────────────────────────────────── /* Contacts — duplicates user /contacts ['type' => 'leaf', 'key' => 'contacts', 'href' => url('/admin/contacts'), 'label' => __('Contacts'), 'icon' => '', 'sw' => 1.5], */ /* Meta Ads — duplicates user top-nav Meta Ads ['type' => 'leaf', 'key' => 'metaads', 'href' => url('/admin/meta-ads'), 'label' => __('Meta Ads'), 'icon' => '', 'sw' => 1.6], */ /* Messaging group — Campaigns/Broadcasts/Templates/Flows/Auto-replies all duplicate the user side ['type' => 'group', 'key' => 'messaging', 'label' => __('Messaging'), 'icon' => '', 'sw' => 1.5, 'children' => [ ['key' => 'campaigns', 'href' => url('/admin/campaigns'), 'label' => __('Campaigns')], ['key' => 'broadcasts', 'href' => url('/admin/broadcasts'), 'label' => __('Broadcasts')], ['key' => 'templates', 'href' => url('/admin/templates'), 'label' => __('Templates'), 'badge' => '38'], ['key' => 'flows', 'href' => url('/admin/flows'), 'label' => __('Flows')], ['key' => 'autoreplies', 'href' => url('/admin/auto-replies'), 'label' => __('Auto-replies')], ]], */ /* Devices — duplicates user /devices ['type' => 'leaf', 'key' => 'devices', 'href' => url('/admin/devices'), 'label' => __('Devices'), 'icon' => '', 'sw' => 1.6, 'badge' => '312'], */ /* Platform group — Integrations + Webhooks both duplicate user side ['type' => 'group', 'key' => 'platform', 'label' => __('Platform'), 'icon' => '', 'sw' => 1.5, 'children' => [ ['key' => 'integrations', 'href' => url('/admin/integrations'), 'label' => __('Integrations')], ['key' => 'webhooks', 'href' => url('/admin/webhooks'), 'label' => __('Webhooks')], ]], */ [ 'type' => 'group', 'key' => 'billing', 'label' => __('Billing & plans'), 'icon' => '', 'sw' => 1.6, 'children' => [ [ 'key' => 'packages', 'href' => url('/admin/packages'), 'label' => __('Packages'), 'badge' => $packagesCount > 0 ? (string) $packagesCount : null, ], [ 'key' => 'credit-packages', 'href' => url('/admin/credit-packages'), 'label' => __('Credit packages'), 'badge' => $creditPackagesCount > 0 ? (string) $creditPackagesCount : null, ], [ 'key' => 'coupons', 'href' => url('/admin/coupons'), 'label' => __('Coupons'), 'badge' => $couponsCount > 0 ? (string) $couponsCount : null, ], [ 'key' => 'billing-history', 'href' => url('/admin/billing-history'), 'label' => __('Billing history'), 'badge' => $billingHistoryCount > 0 ? $fmtCount($billingHistoryCount) : null, ], [ 'key' => 'order-history', 'href' => url('/admin/order-history'), 'label' => __('Order history'), 'badge' => $orderHistoryCount > 0 ? $fmtCount($orderHistoryCount) : null, ], [ 'key' => 'invoices', 'href' => url('/admin/invoices'), 'label' => __('Invoices'), 'badge' => $invoicesCount > 0 ? $fmtCount($invoicesCount) : null, ], // Checkout / pricing controls — tax, refund window, yearly // discount, company invoice identity, AND the auto-renew // (recurring subscriptions) switch. [ 'key' => 'checkout-settings', 'href' => url('/admin/checkout-settings'), 'label' => __('Billing settings'), ], // Wallet rules + affiliate credits — kept inside Billing // because they only control billing-side math (referral // signup credits, credits_per_message, credits_per_currency_minor). [ 'key' => 'wallet-rules', 'href' => url('/admin/settings/wallet-rules'), 'label' => __('Wallet & affiliate'), ], ], ], [ 'type' => 'group', 'key' => 'support', 'label' => __('Support'), 'icon' => '', 'sw' => 1.6, 'badge' => $supportOpen + $contactUnread > 0 ? (string) ($supportOpen + $contactUnread) : null, 'badgeStyle' => 'coral', 'children' => [ [ 'key' => 'support', 'href' => url('/admin/support'), 'label' => __('Inbox'), 'badge' => $supportOpen > 0 ? (string) $supportOpen : null, 'badgeStyle' => 'coral', ], [ 'key' => 'contact-messages', 'href' => url('/admin/contact-messages'), 'label' => __('Contact inbox'), 'badge' => $contactUnread > 0 ? (string) $contactUnread : null, 'badgeStyle' => 'coral', ], [ 'key' => 'support-team', 'href' => url('/admin/support/team-inbox'), 'label' => __('Team inbox'), 'badge' => $supportTeamCount > 0 ? (string) $supportTeamCount : null, ], [ 'key' => 'support-agents', 'href' => url('/admin/support/agents'), 'label' => __('Agents'), 'badge' => $supportAgentsCount > 0 ? (string) $supportAgentsCount : null, ], [ 'key' => 'support-sla', 'href' => url('/admin/support/sla'), 'label' => __('SLA board'), 'badge' => $supportSlaCount > 0 ? (string) $supportSlaCount : null, 'badgeStyle' => $supportSlaCount > 0 ? 'coral' : null, ], [ 'key' => 'support-customers', 'href' => url('/admin/support/customers'), 'label' => __('Customers'), 'badge' => $supportCustomersCount > 0 ? $fmtCount($supportCustomersCount) : null, ], [ 'key' => 'support-playbooks', 'href' => url('/admin/support/playbooks'), 'label' => __('Playbooks'), 'badge' => $supportPlaybooksCount > 0 ? (string) $supportPlaybooksCount : null, ], ['key' => 'support-reports', 'href' => url('/admin/support/reports'), 'label' => __('Reports')], ], ], [ 'type' => 'group', 'key' => 'marketing', 'label' => __('Marketing'), 'icon' => '', 'sw' => 1.5, 'children' => [ [ 'key' => 'announcements', 'href' => url('/admin/announcements'), 'label' => __('Announcements'), 'badge' => $announcementsCount > 0 ? (string) $announcementsCount : null, ], [ 'key' => 'guidebook', 'href' => url('/admin/guidebook'), 'label' => __('Guidebook'), 'badge' => $guidebookCount > 0 ? (string) $guidebookCount : null, ], ], ], /* Analytics — duplicates user /analytics ['type' => 'leaf', 'key' => 'analytics-dup', 'href' => url('/admin/analytics'), 'label' => __('Analytics'), 'icon' => '', 'sw' => 1.6], */ ]; $sys = [ [ 'key' => 'wadesk-message', 'href' => url('/admin/settings/wadesk-message'), 'label' => __('System Message Setting'), 'icon' => '', 'sw' => 1.6, ], // Currencies, Languages, Payment gateways, AI/API keys, Audit // log all live under Settings as tiles now — removed from the // System rail to keep that rail short and focused on what's // genuinely "system": WaDesk message provider, Security, and // the Settings hub itself. [ 'key' => 'frontend', 'href' => url('/admin/frontend'), 'label' => __('Frontend editor'), 'icon' => '', 'sw' => 1.6, ], [ 'key' => 'security', 'href' => url('/admin/security'), 'label' => __('Security'), 'icon' => '', 'sw' => 1.6, ], [ 'key' => 'settings', 'href' => url('/admin/settings'), 'label' => __('Settings'), 'icon' => '', 'sw' => 1.5, ], ]; @endphp
@php // Resolve the logo for the user's currently-selected theme. // Falls back through paper → null. When null we render the // legacy SVG+wordmark so nothing breaks if no logo's uploaded. $brandTheme = \App\Support\Brand::activeTheme(); $brandLogo = \App\Support\Brand::logoUrl($brandTheme); $brandName = (string) \App\Models\SystemSetting::get('app_name', config('app.name', 'WaDesk')); @endphp @if ($brandLogo) {{-- data-brand-logo lets wadesk.js setTheme() swap the src to the matching per-theme logo at theme-change time. --}} {{ $brandName }} @else {{ $brandName }} {{ __('Admin console') }} @endif