@extends('layouts.dashboard')
@section('content')
@php
/**
* Platform Analytics → Revenue: the subscription business behind the marketplace —
* recurring revenue, the movement that produced it, churn, and the share of partner
* sales the platform keeps.
*
* @var array $mrr @var float $arr @var array $arpu
* @var float|null $ltv @var float $grossChurn @var float $netChurn @var array $churnMove @var array $churnSpark
* @var array $takeRate
* @var float $opening @var float $lost @var float $shrunk @var float $grown
* @var array $planStats @var array $accountRows @var array $accountsPager
* @var array $bridgeChart @var array $bridgeMeta @var array $mrrChart @var array $mrrMeta
* @var array $takeChart @var array $takeMeta @var array $arpuChart @var array $arpuMeta
* @var array $planMrrChart @var array $planMrrMeta @var array $statusChart @var array $statusMeta
* @var array $planArpuChart @var array $planArpuMeta
* @var int $rangeDays @var string $rangeMode @var array $rangeLinks
*/
$kpiMeta = static fn (array $m, string $caption): string =>
kpi_trend((int) $m['pct'], (string) $m['dir']) . '' . $caption . '';
// Annual recurring revenue moves exactly as MRR does — it is the same balance read
// over twelve months — so it reuses MRR's own movement rather than a second reading.
$arrMove = ['pct' => $mrr['pct'], 'dir' => $mrr['dir']];
$statusPill = static fn (string $s): string => match ($s) {
'active' => 'qm-pill-green', 'pending' => 'qm-pill-amber', 'cancelled' => 'qm-pill-red', default => 'qm-pill-grey',
};
// Franchise brands the platform's take as a royalty billed on franchise sales, not commission
// kept from a marketplace sale — same figures, franchise wording. Marketplace is the default.
$producesInvoices = $producesInvoices ?? false;
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
{{ t_raw('dashboard.sec.snapshot') }}
{{ t_raw($producesInvoices ? 'admin.analytics.revenue_sub_invoice' : 'admin.analytics.revenue_sub') }}
@foreach ($rangeLinks['options'] as $val => $text)
@php $on = ((string) $val === $rangeLinks['selected']); @endphp
{{ $text }}
@endforeach
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-sync-alt', 'label' => t_raw('admin.analytics.kpi_mrr'),
'value' => money($mrr['total']), 'href' => route('admin.subscriptions'), 'spark' => $mrr['cur'],
'meta' => $kpiMeta($mrr, t('admin.analytics.meta_recurring_run_rate'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-calendar-alt', 'label' => t_raw('admin.analytics.kpi_arr'),
'value' => money($arr), 'spark' => $mrr['cur'],
'meta' => $kpiMeta($arrMove, t('admin.analytics.meta_mrr_annualised'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'rose', 'icon' => 'fa-user-slash', 'label' => t_raw('admin.analytics.kpi_gross_churn'),
'value' => number_format($grossChurn, 1) . '%', 'spark' => $churnSpark,
'meta' => $kpiMeta($churnMove, t('admin.analytics.meta_of_opening_mrr'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-user-tag', 'label' => t_raw('admin.analytics.kpi_arpu'),
'value' => money($arpu['total']), 'spark' => $arpu['cur'],
'meta' => $kpiMeta($arpu, t('admin.analytics.meta_per_paying_account'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-infinity', 'label' => t_raw('admin.analytics.kpi_ltv'),
'value' => $ltv !== null ? money($ltv) : "\u{2014}", 'spark' => $arpu['cur'],
'meta' => '' . ($ltv !== null ? t('admin.analytics.meta_arpu_over_churn') : t('admin.analytics.meta_needs_churn_history')) . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-percentage', 'label' => t_raw($producesInvoices ? 'admin.analytics.kpi_royalty_rate' : 'admin.analytics.kpi_take_rate'),
'value' => number_format($takeRate['total'], 1) . '%', 'spark' => $takeRate['cur'],
'meta' => $kpiMeta($takeRate, t($producesInvoices ? 'admin.analytics.meta_royalty_over_gmv' : 'admin.analytics.meta_commission_over_gmv'))])
{{ t_raw('dashboard.sec.trends') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_mrr_movement'), 'sub' => t_raw('admin.analytics.chart_mrr_movement_caption'), 'cfg' => $bridgeChart, 'meta' => $bridgeMeta, 'icon' => 'fa-chart-bar', 'accent' => 'green', 'opts' => ['id' => 'admRevMovementChart', 'url' => route('admin.chart-series', ['chart' => 'revMovement']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_mrr_level'), 'sub' => t_raw('admin.analytics.chart_mrr_level_caption'), 'cfg' => $mrrChart, 'meta' => $mrrMeta, 'accent' => 'teal', 'opts' => ['id' => 'mrrChart', 'url' => route('admin.chart-series', ['chart' => 'revMrr']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw($producesInvoices ? 'admin.analytics.chart_gmv_vs_royalty' : 'admin.analytics.chart_gmv_vs_commission'), 'sub' => t_raw($producesInvoices ? 'admin.analytics.chart_gmv_vs_royalty_caption' : 'admin.analytics.chart_gmv_vs_commission_caption'), 'cfg' => $takeChart, 'meta' => $takeMeta, 'icon' => 'fa-chart-bar', 'accent' => 'blue', 'opts' => ['id' => 'admRevTakeChart', 'url' => route('admin.chart-series', ['chart' => 'revTake']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_arpu_over_time'), 'sub' => t_raw('admin.analytics.chart_arpu_over_time_caption'), 'cfg' => $arpuChart, 'meta' => $arpuMeta, 'accent' => 'violet', 'opts' => ['id' => 'arpuChart', 'url' => route('admin.chart-series', ['chart' => 'revArpu']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
{{ t_raw('dashboard.sec.breakdown') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_mrr_by_plan'), 'sub' => t_raw('admin.analytics.chart_mrr_by_plan_caption'), 'cfg' => $planMrrChart, 'meta' => $planMrrMeta, 'icon' => 'fa-chart-pie', 'accent' => 'green'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_sub_status_mix'), 'sub' => t_raw('admin.analytics.chart_sub_status_mix_caption'), 'cfg' => $statusChart, 'meta' => $statusMeta, 'icon' => 'fa-chart-pie', 'accent' => 'blue'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_arpu_by_plan'), 'sub' => t_raw('admin.analytics.chart_arpu_by_plan_caption'), 'cfg' => $planArpuChart, 'meta' => $planArpuMeta, 'icon' => 'fa-chart-bar', 'accent' => 'violet'])
{{ t_raw('admin.analytics.caption_plan_economics') }}
| {{ t_raw('common.plan') }} |
{{ t_raw('admin.analytics.kpi_active_subs') }} |
{{ t_raw('admin.analytics.kpi_mrr') }} |
{{ t_raw('admin.analytics.kpi_arpu') }} |
{{ t_raw($producesInvoices ? 'admin.analytics.col_royalty_rate' : 'admin.analytics.col_commission_rate') }} |
{{ t_raw($producesInvoices ? 'admin.analytics.series_gmv_invoice' : 'admin.analytics.series_gmv') }} |
{{ t_raw($producesInvoices ? 'common.royalty' : 'common.commission') }} |
{{ t_raw($producesInvoices ? 'admin.analytics.kpi_royalty_rate' : 'admin.analytics.kpi_take_rate') }} |
@if ($planStats)
@foreach ($planStats as $row)
| {!! plan_tag($row['slug'], $row['name']) !!} |
{{ number_format((int) $row['subs']) }} |
{{ money($row['mrr']) }} |
{!! (int) $row['subs'] > 0 ? money($row['mrr'] / (int) $row['subs']) : dash() !!} |
{{ number_format((float) $row['rate'], 2) }}% |
{!! (float) $row['gmv'] > 0 ? money($row['gmv']) : dash() !!} |
{!! (float) $row['commission'] > 0 ? money($row['commission']) : dash() !!} |
{!! (float) $row['gmv'] > 0 ? number_format((float) $row['commission'] / (float) $row['gmv'] * 100, 1) . '%' : dash() !!} |
@endforeach
@else
@partial('table-empty', ['colspan' => 8, 'icon' => 'fa-layer-group', 'msg' => t('admin.analytics.empty_no_active_plans')])
@endif
{{ t_raw('admin.analytics.caption_recurring_accounts') }}
| {{ t_raw('common.restaurant') }} |
{{ t_raw('common.plan') }} |
{{ t_raw('common.status') }} |
{{ t_raw('admin.analytics.kpi_mrr') }} |
{{ t_raw($producesInvoices ? 'admin.analytics.col_royalty_rate' : 'admin.analytics.col_commission_rate') }} |
{{ t_raw('admin.analytics.col_started') }} |
{{ t_raw('admin.analytics.col_renews') }} |
@if ($accountRows)
@foreach ($accountRows as $row)
{!! restaurant_logo_html(['logo' => $row['logo'], 'name' => $row['restaurant']], 'md') !!}
{!! or_dash($row['restaurant']) !!}{!! $row['live'] ? t('admin.analytics.badge_contributing') : t('admin.analytics.badge_not_contributing') !!}
|
{!! plan_tag($row['plan_slug'], $row['plan']) !!} |
{{ status_label('subscription', $row['status']) }} |
{!! $row['mrr'] > 0 ? money($row['mrr']) : dash() !!} |
{{ number_format((float) $row['rate'], 2) }}% |
{!! fmt_day($row['starts_at']) !!} |
{!! $row['ends_at'] ? fmt_day($row['ends_at']) : dash() !!} |
@endforeach
@else
@partial('table-empty', ['colspan' => 7, 'icon' => 'fa-file-invoice-dollar', 'msg' => t('admin.analytics.empty_no_subscriptions')])
@endif
@partial('table-toolbar', ['pager' => $accountsPager, 'base' => '/admin/analytics/revenue'])
@php /* /.qm-d2 */
@endphp
@endsection