{{ __('Operator Dashboard') }} Live · synced 4s ago

{{ $greeting }}, {{ $userName }}. @if ($broadcastsRunning > 0) {{ $broadcastsRunning }} broadcast{{ $broadcastsRunning === 1 ? '' : 's' }} are running. @else {{ __('Workspace is calm.') }} @endif

{{ $today }} · Last 7 days showing {{ number_format($sent24h) }} outbound, {{ $deliverabilityPct }}% deliverability across {{ $devicesActive }} connected device{{ $devicesActive === 1 ? '' : 's' }}.

{{-- Export — client-side CSV of the daily throughput series (sent / delivered / failed) wired in user-dashboard-index.js. --}} {{-- Date range — drives the throughput chart range below (same datasets as the in-card 24h/7d/30d/QTD toggle). --}}
New campaign
@php $deltaPill = function ($delta, $invertGood = false) { $up = $delta >= 0; $good = $invertGood ? !$up : $up; $css = $good ? 'bg-wa-bubble text-wa-deep' : 'bg-accent-coral/10 text-[#A1431F]'; $arrow = $up ? '▲' : '▼'; return [$css, $arrow, abs((float) $delta)]; }; $kpiPctW = function ($num, $denom, $cap = 100) { if ($denom <= 0) { return 0; } return max(0, min($cap, (int) round(($num / $denom) * 100))); }; @endphp @php [$sentCss, $sentArrow, $sentVal] = $deltaPill($deltaSent); @endphp
{{ __('Messages sent · 7d') }} {{ $sentArrow }} {{ $sentVal }}%
{{ number_format($sent24h) }}
{{ number_format($delivered24h) }} {{ __('delivered') }} {{ number_format($failed24h) }} {{ __('failed') }}
@php $rrUp = $deltaReadRate >= 0; $rrCss = $rrUp ? 'bg-paper-100 text-ink-700' : 'bg-accent-coral/10 text-[#A1431F]'; $rrArr = $rrUp ? '▲' : '▼'; @endphp
{{ __('Read rate') }} {{ $rrArr }} {{ abs($deltaReadRate) }}pp
{{ $readRatePct }}%
{{ __('Sent') }}
{{ $sent24h > 0 ? '100%' : '0%' }}
{{ __('Deliv') }}
{{ $deliverabilityPct }}%
{{ __('Read') }}
{{ $readRatePct }}%
@php [$cCss, $cArrow, $cVal] = $deltaPill($deltaContacts); @endphp
{{ __('Active contacts') }} {{ $cArrow }} {{ $cVal }}%
{{ number_format($contactsTotal) }}
{{ __('Subscribed') }}
{{ number_format($contactsSubscribed) }}
{{ __('Opted-in') }}
{{ number_format($contactsOpted) }}
{{ __('Blocked') }}
{{ number_format($contactsBlocked) }}
{{ __('Credit balance') }} {{ $creditsPerMessage ?? 1 }} credit{{ ($creditsPerMessage ?? 1) === 1 ? '' : 's' }} = 1 msg
{{ number_format($walletCredits ?? 0) }} {{ __('credits') }}
≈ {{ number_format($estMessages ?? 0) }} message{{ ($estMessages ?? 0) === 1 ? '' : 's' }} {{ __('Earn via affiliate →') }}
{{ __('Top up credits →') }}

{{ __('Message throughput') }}

{{ __('UTC+1') }}

{{ __('Outbound, delivered & failed events — daily, last 7 days.') }}

@php $fmt = function ($n) { $n = (int) $n; if ($n >= 1000000) { return rtrim(rtrim(number_format($n / 1000000, 1), '0'), '.') . 'M'; } if ($n >= 1000) { return rtrim(rtrim(number_format($n / 1000, 1), '0'), '.') . 'k'; } return (string) $n; }; @endphp
{{ __('Sent') }} {{ $fmt($sent24h) }} {{ __('Delivered') }} {{ $fmt($delivered24h) }} {{ __('Failed') }} {{ $fmt($failed24h) }} @if (($peakHour['sent'] ?? 0) > 0) {{ __('Peak hour') }} {{ $peakHour['label'] }} · {{ number_format((int) $peakHour['sent']) }} {{ __('msg') }} @endif
{{ __('Avg / hour') }}
{{ number_format($avgPerHour) }}
{{ __('Replies') }}
{{ number_format($replies24h) }}
{{ __('Reply rate') }}
{{ $replyRatePct }}%
{{ __('Failed') }}
{{ number_format($failed24h) }}

{{ __('Active campaigns') }}

{{ $broadcastsRunning }} running · {{ $broadcastsScheduled }} scheduled · {{ $broadcastsPaused }} {{ __('paused') }}

View all {{ $broadcastsTotal }} →
@forelse ($activeCampaigns as $bc)
{{ $bc['name'] ?: 'Untitled broadcast' }} @if (in_array($bc['status'], ['Sending'], true)) @endif {{ $bc['status'] }}
{{ $bc['category'] }}{{ $bc['template'] ? ' · ' . $bc['template'] : '' }}
{{ __('delivered') }}
{{ number_format($bc['done']) }} / {{ number_format($bc['total']) }}
{{ $bc['pct'] }}%
@empty
{{ __('No active broadcasts') }}

{{ __('Spin one up to start sending to a contact group.') }}

+ New broadcast
@endforelse

{{ __('Connected devices') }}

{{ $devicesTotal }} of {{ $deviceSlotCap }} slots used · {{ $devicesActive }} {{ __('online') }}

+ Connect
@forelse ($devicesList as $i => $dev) @php $dotColor = $dev['is_online'] ? 'bg-wa-green' . ($i === 0 ? ' glow-green shadow-[0_0_0_4px_rgba(37,211,102,0.18)]' : '') : ($dev['status'] === 'connecting' ? 'bg-accent-amber' : 'bg-accent-coral'); $delivColor = $dev['deliv_pct'] >= 95 ? '' : ($dev['deliv_pct'] >= 85 ? 'text-accent-amber' : 'text-accent-coral'); $regionLabel = $dev['region'] ?: 'unzoned'; @endphp
WA
{{ $dev['phone'] }}
{{ $dev['label'] }} · {{ $regionLabel }} · {{ number_format($dev['sent_24h']) }}/24h
{{ $dev['deliv_pct'] }}%
{{ __('deliv') }}
@empty
{{ __('No devices connected') }}

{{ __('Pair a WhatsApp number to start sending.') }}

@endforelse
@php $slotsLeft = max(0, $deviceSlotCap - $devicesTotal); @endphp @if ($slotsLeft > 0)
{{ $slotsLeft }} device slot{{ $slotsLeft === 1 ? '' : 's' }} {{ __('available') }}
{{ __('Add WABA, Unofficial API, or Twilio') }}
{{ __('Connect device') }}
@endif

{{ __('Top performing templates') }}

{{ __('By send volume · last 7 days · Meta-approved only') }}

{{ $templatesCount }} template{{ $templatesCount === 1 ? '' : 's' }} + New template
@forelse ($topTemplates as $t) @php $statusKey = strtolower((string) $t['status']); $statusPill = match (true) { in_array($statusKey, ['approved', 'active'], true) => [ 'Approved', 'bg-wa-green/15 text-wa-deep', ], in_array($statusKey, ['pending', 'submitted', 'in_review'], true) => [ 'In review', 'bg-accent-amber/20 text-[#8B5A14]', ], in_array($statusKey, ['rejected', 'disabled'], true) => [ 'Rejected', 'bg-accent-coral/15 text-accent-coral', ], default => [ucfirst($statusKey ?: 'Draft'), 'bg-paper-100 text-ink-700'], }; $catShort = strtoupper(substr((string) $t['category'], 0, 3)) ?: 'TPL'; $catColor = match ($catShort) { 'MAR', 'UTI' => ['bg-wa-bubble', 'text-wa-deep'], 'AUT' => ['bg-accent-amber/20', 'text-accent-amber'], default => ['bg-paper-100', 'text-ink-700'], }; @endphp @empty @endforelse
{{ __('Template') }} {{ __('Type') }} {{ __('Sent') }} {{ __('Delivered') }} {{ __('Read') }} {{ __('CTR') }} {{ __('Performance') }} {{ __('Status') }}
{{ $catShort }}
{{ $t['name'] }}
id: tpl_{{ $t['id'] }} · {{ strtoupper((string) $t['language']) ?: '—' }}
{{ $t['category'] }}{{ $t['type'] && $t['type'] !== '—' ? ' · ' . $t['type'] : '' }} {{ $t['sends'] > 0 ? number_format($t['sends']) : '—' }} {{ $t['sends'] > 0 ? number_format($t['delivered']) : '—' }} {{ $t['sends'] > 0 ? number_format($t['read']) : '—' }} {{ $t['ctr'] !== null ? $t['ctr'] . '%' : '—' }}
{{ $t['perf'] > 0 ? $t['perf'] : '—' }}
{{ $statusPill[0] }}
{{ __('No templates yet.') }} {{ __('Create your first →') }}

{{ __('Live inbox') }}

{{ $unreadCount }} unread @if ($oldestUnreadAgo) · oldest {{ $oldestUnreadAgo }} @endif

{{ __('Open inbox →') }}
{{ __('Recent conversations') }} {{ $unreadCount }} {{ __('unread') }}
@forelse ($liveConvos as $i => $c) @php $gradients = [ 'from-accent-coral to-accent-amber', 'from-wa-teal to-wa-deep', 'from-accent-amber to-accent-coral', ]; $grad = $gradients[$i % count($gradients)]; @endphp {{ $c['initials'] }}
{{ $c['title'] }} {{ $c['ago'] }}
{{ $c['preview'] }}
@if ($c['unread'] > 0) {{ $c['unread'] }} @endif
@empty
{{ __('No conversations yet.') }}
@endforelse
AI {{ \App\Models\SystemSetting::get('app_name', config('app.name', 'WaDesk')) }} {{ __('Copilot') }} {{ __('GPT-4o') }}

{{ __('Build a flow from a sentence.') }}

{{ __('Describe a customer journey and Copilot drafts nodes, branches, and template suggestions.') }}

@php $copilotExample = 'When a WooCommerce order is paid, send a thank-you with tracking link. After 24h, ask for a 5-star review and offer a 10% off coupon.'; @endphp
{{ __('try:') }}
"{{ $copilotExample }}"
{{ __('flows') }}
{{ number_format($copilotFlows ?? 0) }}
{{ __('active') }}
{{ number_format($copilotActive ?? 0) }}
{{ __('subscribers') }}
{{ number_format($copilotSubscribers ?? 0) }}

{{ __('Automation flows') }}

{{ number_format($copilotActive ?? 0) }} {{ __('active') }} · {{ number_format($copilotSubscribers ?? 0) }} {{ __('subscribers') }}

{{ __('Open') }}

{{ __('Engagement funnel') }}

{{ __('Workspace activity · last 7 days') }}

{{ __('view all →') }}
@php $stepStyles = ['bg-wa-deep text-paper-0', 'bg-wa-teal/15', 'bg-wa-green/20', 'bg-paper-50']; $barColors = ['bg-paper-0/30', 'bg-wa-deep/30', 'bg-wa-deep/25', 'bg-wa-deep/20']; @endphp
@foreach ($funnelSteps as $i => $step) @php $isFirst = $i === 0; // Internal progress bar — width 100% always so stages // render at equal card width and don't visually collapse // to 8% when count=0. The bar inside shows the funnel. $barPct = max(0.0, min(100.0, (float) $step['pct'])); $rowStyle = $stepStyles[$i] ?? 'bg-paper-50'; $barColor = $barColors[$i] ?? 'bg-wa-deep/20'; $labelMono = $isFirst ? 'text-paper-0/60' : 'text-ink-500'; $valColor = $isFirst ? 'text-paper-0/60' : 'text-ink-500'; @endphp @if (!$isFirst)
↓ {{ $step['pct'] }}%
@endif
{{ $step['stage'] }}
{{ $step['label'] }}
{{ number_format($step['count']) }}
{{ $isFirst ? '100%' : '↘ ' . number_format($step['drop']) }}
@endforeach
{{ __('end-to-end conversion') }} {{ $funnelEndPct }}% {{ count($funnelSteps) }} stage{{ count($funnelSteps) === 1 ? '' : 's' }}

{{ __('Activity log') }}

{{ __('Workspace events · auto-refresh') }}

{{-- Events grow to fill the card height; with space-evenly the items distribute through the available vertical space so short event lists don't leave a big empty area below. --}}
    @if (count($events)) @endif @forelse ($events as $idx => $ev) @php $initials = strtoupper( substr(preg_replace('/[^A-Za-z]/', '', (string) ($ev['actor'] ?? 'NA')), 0, 2), ) ?: 'NA'; $shortSubject = class_basename($ev['subject'] ?? ''); $subjectLabel = strtolower(\Illuminate\Support\Str::snake($shortSubject ?: 'event')); @endphp
  1. {{ $initials }}
    {{ $ev['actor'] }} · {{ $ev['action'] }}{{ $shortSubject ? ' — ' . $shortSubject : '' }}
    {{ $ev['ago'] }} ago{{ $subjectLabel ? ' · ' . $subjectLabel : '' }}
  2. @empty
  3. {{ __('No recent activity logged for this workspace.') }}
  4. @endforelse

{{ __('Quick actions') }}

{{ __('Integrations') }}

{{ $integrationsConnected }} / {{ $integrationsTotal }}
@foreach ($integrations as $intg)
{{ $intg['badge'] }}
{{ $intg['name'] }}
{{ $intg['detail'] }}
@if ($intg['connected']) @else {{ __('Connect') }} @endif
@endforeach