@props([ 'title' => 'Dashboard', 'navKey' => 'dashboard', 'page' => null, 'hideHeader' => false, ]) {{-- Sub-folder base path (e.g. /public) so client-side AJAX honours the deploy location under a sub-directory. --}} {{-- Active currency symbol (workspace override → platform default) for chart JS so axes/tooltips follow the chosen currency, not '$'. --}} @php $faviconUrl = \App\Support\Brand::faviconUrl(); @endphp @if ($faviconUrl) @endif {{-- Server flash → toast. Any controller that does redirect()->with('status' / 'success' / 'error') ends up here as a meta tag, and resources/js/wa-toaster.js shows it on DOMContentLoaded. Keeps UI feedback consistent without each page rolling its own banner. --}} @php $flashVariant = session('error') ? 'error' : (session('warning') ? 'warn' : 'success'); $flashMessage = session('error') ?? (session('warning') ?? (session('success') ?? session('status'))); @endphp @if ($flashMessage) $flashVariant, 'message' => $flashMessage])'> @endif @php $__brandName = (string) \App\Models\SystemSetting::get('app_name', config('app.name', 'WaDesk')); @endphp {{ $title }} — {{ $__brandName }} {{-- SEO meta block — single source at /admin/settings/seo. --}} @include('partials.seo-meta', ['seoOverrides' => ['title' => $title . ' — ' . $__brandName]]) @include('partials.pwa-meta') @include('partials.site-analytics') @php // Per-theme logo URLs for live theme-switch in wadesk.js. $brandLogos = []; foreach (['paper', 'bright', 'dark', 'doodle'] as $__t) { $brandLogos[$__t] = \App\Support\Brand::logoUrl($__t); } @endphp {{-- Sprint 6 · Branding tab — workspace-scoped brand colors get emitted as CSS vars AND class overrides. Only renders when at least one brand_* column is set on the current workspace; otherwise the default Tailwind palette wins. --}} @auth @php $brandWs = auth()->user()->currentWorkspace; @endphp @if ($brandWs && ($brandWs->brand_primary || $brandWs->brand_accent || $brandWs->brand_background)) @endif @endauth @auth @endauth @vite(['resources/css/app.css', 'resources/js/app.js']) {{-- Impersonation strip — only present when ImpersonationBanner middleware shared a non-null `$impersonation`. Sticky so it survives scroll on every page; the form posts to /admin/impersonate/stop which clears the session and audit-logs the duration. --}} @if (!empty($impersonation) && ($impersonation['active'] ?? false))
{{ __('Impersonating') }} {{ $impersonation['target_workspace_name'] ?? 'workspace' }}
@csrf
@endif @unless ($hideHeader) @endunless {{ $slot }} {{-- In-app paywall — slides up over the page when the current plan doesn't include the feature being viewed. Self-guards (admins / unlocked / non-gated pages render nothing). --}} {{-- GDPR cookie consent — auto-opens on first visit; admin can disable globally at /admin/settings/pwa. --}} @include('partials.cookie-consent') @stack('scripts') @auth {{-- Global "new messages" notification widget. Appears bottom-right on every page EXCEPT the team-inbox itself (where you already see the chats live). Polls /team-inbox/api/unread-summary every 15s, pauses when the tab is hidden, exponential backoff on 429 / errors. --}} @if (in_array($navKey, ['team-inbox'], true) === false) @endif @endauth