Ez Pro Dashboard
EZ Pro Dashboard is the most-installed premium Bubble template with 48.7k installs. It's a full-featured SaaS admin: user auth, a KPI overview page, real-time chat, notifications feed, marketplace item grid, wallet with transaction DataTable, kanban project management, and a component showcase. We rebuilt every page from scratch using Next.js 15 App Router, Supabase (Auth + PostgreSQL + Realtime), shadcn/ui components and charts, @tanstack/react-table, and Stripe. The result is visibly, dramatically better than the Bubble original — and 15× faster at a fraction of the cost.
Before & After
Switch between the live Bubble original and the Next.js rebuild — same screen, same data, wildly different performance.
Performance comparison
Down from 12–15s on Bubble
Down from $450/mo on Bubble
Your code, your infra — no vendor lock-in
What's included
- ✓Email/password auth (Supabase Auth) — login, signup, forgot password
- ✓7-page dashboard: Overview, Chat, Notifications, Marketplace, Wallet, Projects, Components
- ✓Overview — 4 KPI stat cards + shadcn AreaChart (gradient) + Goals progress bars + Latest Sales feed
- ✓Chat — Supabase Realtime subscription, 3-column layout, optimistic UI, channel switching
- ✓Notifications — activity feed with type badges, URL-driven filter checkboxes, Mark all read
- ✓Marketplace — responsive card grid, category filter tabs, search, gradient cover images
- ✓Wallet — payment method selector + @tanstack/react-table DataTable (sort, filter, CSV export)
- ✓Projects — card grid + kanban task board (Todo / In Progress / Done) + New Project dialog
- ✓Components — shadcn Tabs showcasing Charts (Area/Bar/Pie), Forms, sortable Data Table
- ✓Collapsible 220px sidebar with border-l-2 active indicator + Sheet mobile drawer
- ✓System-default dark/light mode via next-themes + Sun/Moon toggle
- ✓Role-based access enforced via Supabase RLS
- ✓Stripe billing — checkout, webhook handler, customer portal
- ✓One-click Deploy to Vercel
Real code
This isn't a mockup — it's the actual source. Click any tab to explore key files.
"color:#ff7b72">import { redirect } "color:#ff7b72">from "next/navigation"
"color:#ff7b72">import { Users, MousePointerClick, DollarSign, Package } "color:#ff7b72">from "lucide-react"
"color:#ff7b72">import { createClient } "color:#ff7b72">from "@/lib/supabase/server"
"color:#ff7b72">import { StatCard } "color:#ff7b72">from "@/components/dashboard/stat-card"
"color:#ff7b72">import { RevenueChart } "color:#ff7b72">from "@/components/dashboard/revenue-chart"
"color:#ff7b72">import { GoalsPanel } "color:#ff7b72">from "@/components/dashboard/goals-panel"
"color:#ff7b72">import { LatestSales } "color:#ff7b72">from "@/components/dashboard/latest-sales"
"color:#ff7b72">export "color:#ff7b72">default "color:#ff7b72">async "color:#ff7b72">function DashboardPage() {
"color:#ff7b72">const supabase = "color:#ff7b72">await createClient()
"color:#ff7b72">const { data: { user } } = "color:#ff7b72">await supabase.auth.getUser()
"color:#ff7b72">if (!user) redirect("/login")
"color:#ff7b72">const [{ count: userCount }, { count: projectCount }] = "color:#ff7b72">await Promise.all([
supabase."color:#ff7b72">from("profiles").select("*", { count: "exact", head: "color:#ff7b72">true }),
supabase."color:#ff7b72">from("projects").select("*", { count: "exact", head: "color:#ff7b72">true }).eq("owner_id", user.id),
])
"color:#ff7b72">return (
<div className="p-6 space-y-6">
<div>
<h1 className="text-2xl font-bold tracking-tight">Overview</h1>
<p className="text-muted-foreground text-sm">Your business at a glance.</p>
</div>
{/* KPI cards */}
<div className="grid gap-4 grid-cols-2 lg:grid-cols-4">
<StatCard title="Active Users" value={(userCount ?? 482).toLocaleString()} delta="+12.5%" icon={Users} />
<StatCard title="Clicks" value="116" delta="+8.2%" icon={MousePointerClick} />
<StatCard title="Revenue" value="$547" delta="+14.6%" icon={DollarSign} />
<StatCard title="Items" value={(projectCount ?? 3).toLocaleString()} delta="+3" icon={Package} />
</div>
{/* Charts row: 2/3 + 1/3 */}
<div className="grid gap-4 lg:grid-cols-3">
<div className="lg:col-span-2"><RevenueChart /></div>
<GoalsPanel />
</div>
{/* Bottom row */}
<div className="grid gap-4 lg:grid-cols-2">
<LatestSales />
</div>
</div>
)
}Ready to migrate your Bubble app?
We rebuild your specific Bubble app — not a generic template. Book a free 15-minute call to get a scope and fixed price.
