@php // Compute first-run setup state. All three cards always render so the // user can see at a glance what's connected vs. what's still pending, // AND keep adding more (more email accounts, more contacts, tweak AI). // Connected cards show a green check + a count + the action link // becomes "Connect another" / "Import more" / "Tune it" instead of // being struck through. $wsId = auth()->user()?->active_workspace_id; $emailCount = $wsId ? \App\Models\EmailAccount::where('workspace_id', $wsId)->where('status', 'connected')->count() : 0; // Pluck the connected provider slugs so each card can render a small // row of brand-style badges (Gmail / Outlook / IMAP / Custom). $emailProviders = $wsId ? \App\Models\EmailAccount::where('workspace_id', $wsId)->where('status', 'connected')->pluck('provider')->unique()->values()->all() : []; $hasEmail = $emailCount > 0; // AI is "ready" only when a usable API key is resolvable — either // the workspace stored its own key, or the platform has a global // provider key configured. The default ai_configs row created // during onboarding shouldn't, by itself, mark AI as ready. $hasAiConfig = false; if ($wsId) { $aiConfig = \App\Models\AiConfig::where('workspace_id', $wsId)->first(); if ($aiConfig) { $ownKey = $aiConfig->use_own_key && !empty($aiConfig->getRawOriginal('api_key')); $platformKey = !empty(config('services.openai.api_key')) || !empty(config('services.anthropic.api_key')) || !empty(config('services.gemini.api_key')) || !empty(config('services.mistral.api_key')); $hasAiConfig = $ownKey || (!$aiConfig->use_own_key && $platformKey); } } $contactCount = $wsId ? \App\Models\Contact::where('workspace_id', $wsId)->count() : 0; $hasContacts = $contactCount > 0; $tourSteps = [ [ 'key' => 'email', 'href' => url('/settings/email'), 'title' => __('Connect Email'), 'subtitle' => __('Link your inbox'), 'done' => $hasEmail, 'done_title' => __('Email Connected'), 'done_subtitle' => trans_choice(':count account connected|:count accounts connected — connect more', $emailCount, ['count' => $emailCount]), 'done_cta' => __('Add another account'), 'providers' => $emailProviders, 'svg' => 'M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z', ], [ 'key' => 'ai', 'href' => url('/settings/ai'), 'title' => __('Train Your AI'), 'subtitle' => __('Configure responses'), 'done' => $hasAiConfig, 'done_title' => __('AI Ready'), 'done_subtitle' => __('Configured — keep refining responses'), 'done_cta' => __('Tune settings'), 'providers' => [], 'svg' => 'M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z', ], [ 'key' => 'contacts', 'href' => url('/contacts'), 'title' => __('Import Contacts'), 'subtitle' => __('Add your people'), 'done' => $hasContacts, 'done_title' => __('Contacts Imported'), 'done_subtitle' => trans_choice(':count contact — import more|:count contacts — import more', $contactCount, ['count' => number_format($contactCount)]), 'done_cta' => __('Import more'), 'providers' => [], 'svg' => 'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z', ], ]; $doneCount = collect($tourSteps)->where('done', true)->count(); // Small inline SVG badges for each provider slug — keeps the "which // channel is connected" visual without pulling a whole icon library. $providerBadge = function (string $p): string { $cls = 'w-3.5 h-3.5'; return match ($p) { 'gmail' => '', 'outlook' => '', 'imap', 'custom' => '', default => '', }; }; $providerLabel = fn (string $p) => match ($p) { 'gmail' => 'Gmail', 'outlook' => 'Outlook', 'imap' => 'IMAP', 'custom' => 'Custom', default => ucfirst($p), }; @endphp {{-- Product Tour — always renders all three setup steps. Connected cards stay actionable so the user can add more email accounts, import more contacts, or re-tune the AI without the "you're done, go away" feel of a strike-through. The user can collapse the panel (chevron toggle) but it never dismisses permanently — the state is remembered in localStorage so reloads respect it. --}}
{{-- Chevron toggle — rotates 180° when the panel is collapsed so the user has a visual cue that clicking again will re-expand. Replaces the old permanent-dismiss "X". --}}

{{ __('Welcome to') }} {{ config('app.name') }}!

@if($doneCount === 0) {{ __('Here are your first steps to get up and running:') }} @elseif($doneCount < count($tourSteps)) {{ __('Setup progress') }}: {{ $doneCount }}/{{ count($tourSteps) }} — {{ __('keep going!') }} @else {{ __('You\'re all set — keep growing your workspace.') }} @endif

{{-- Skeleton loader: shown instantly while Livewire component hydrates --}}
{{-- Skeleton placeholder --}}
{{-- Page title skeleton --}}
{{-- Stats cards skeleton: 4 cards --}}
@for ($i = 0; $i < 4; $i++)
@endfor
{{-- Charts row skeleton: 2 charts --}}
@for ($i = 0; $i < 2; $i++)
@endfor
{{-- Bottom section skeleton: recent activity + quick actions --}}
@for ($i = 0; $i < 5; $i++)
@endfor
@for ($i = 0; $i < 4; $i++)
@endfor
{{-- Actual Livewire component --}}
{{-- Actionable Insights --}}