60 lines
3.1 KiB
JavaScript
60 lines
3.1 KiB
JavaScript
import React from 'react'
|
|
import { Head } from '@inertiajs/react'
|
|
import AdminLayout from '../../../Layouts/AdminLayout'
|
|
import AnalyticsNav from './AnalyticsNav'
|
|
|
|
function StatCard({ label, value }) {
|
|
return (
|
|
<div className="rounded-2xl border border-white/[0.08] bg-white/[0.04] p-5">
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">{label}</p>
|
|
<p className="mt-3 text-3xl font-bold text-white">{Number(value || 0).toLocaleString()}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function AcademyAnalyticsFunnel({ nav = [], range, summary = {}, bestConverters = [] }) {
|
|
return (
|
|
<AdminLayout title="Academy Funnel" subtitle="Early conversion signals from premium previews, upgrade clicks, and learning starts.">
|
|
<Head title="Admin · Academy Funnel" />
|
|
|
|
<div className="space-y-6">
|
|
<AnalyticsNav items={nav} />
|
|
|
|
<div className="rounded-[28px] border border-white/[0.08] bg-white/[0.03] p-6">
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">Range</p>
|
|
<p className="mt-3 text-sm text-slate-300">{range?.from} to {range?.to}</p>
|
|
</div>
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
|
<StatCard label="Academy Visitors" value={summary.academyVisitors} />
|
|
<StatCard label="Premium Preview Views" value={summary.premiumPreviewViews} />
|
|
<StatCard label="Upgrade Clicks" value={summary.upgradeClicks} />
|
|
<StatCard label="Learning Starts" value={summary.starts} />
|
|
<StatCard label="Completions" value={summary.completions} />
|
|
<StatCard label="Checkout Starts" value={summary.checkoutStarts} />
|
|
<StatCard label="Subscriptions" value={summary.subscriptions} />
|
|
</div>
|
|
|
|
<div className="rounded-[28px] border border-white/[0.08] bg-white/[0.03] p-6">
|
|
<p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">Best Converting Content</p>
|
|
<div className="mt-4 space-y-3">
|
|
{bestConverters.length ? bestConverters.map((item) => (
|
|
<div key={`${item.content_type}-${item.content_id || 'none'}`} className="rounded-2xl border border-white/[0.08] bg-black/20 px-4 py-4">
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
<div>
|
|
<p className="font-semibold text-white">{item.title}</p>
|
|
<p className="mt-1 text-xs uppercase tracking-[0.18em] text-slate-500">{item.content_type_label}</p>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="text-sm font-semibold text-sky-100">{item.conversion_score}</p>
|
|
<p className="text-xs uppercase tracking-[0.18em] text-slate-500">conversion</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)) : <p className="rounded-2xl border border-dashed border-white/[0.08] bg-black/20 px-4 py-6 text-sm text-slate-400">No conversion signals have been rolled up yet.</p>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AdminLayout>
|
|
)
|
|
} |