import { redirect } from "next/navigation"
import { eq } from "drizzle-orm"
import { db } from "@/lib/db"
import { profiles } from "@/lib/db/schema"
import { getSessionUser } from "@/lib/session"
import {
getDashboardStats,
getRecentRentPayments,
getOpenMaintenanceRequests,
getExpiringLeases,
getMonthlyRevenue,
getExpenseBreakdown,
} from "@/lib/db/queries"
import { StatsCard } from "@/components/dashboard/stats-card"
import { RevenueChart } from "@/components/dashboard/revenue-chart"
import { ExpenseBreakdownChart } from "@/components/dashboard/expense-breakdown-chart"
import { QuickActions } from "@/components/dashboard/quick-actions"
import { RentStatusBadge } from "@/components/dashboard/rent-status-badge"
import { MaintenanceStatusBadge, PriorityBadge } from "@/components/dashboard/maintenance-status-badge"
import { EmptyState } from "@/components/shared/empty-state"
import { formatCurrency, formatDate, daysUntil } from "@/lib/utils"
import {
Building2, CreditCard, Wrench, TrendingUp,
AlertTriangle, ArrowRight, CheckCircle2, Clock,
Sparkles, ChevronRight,
} from "lucide-react"
import Link from "next/link"
function GreetingBanner({ name }: { name: string }) {
const hour = new Date().getHours()
const greeting = hour < 12 ? "Good morning" : hour < 17 ? "Good afternoon" : "Good evening"
const now = new Date()
const dateStr = now.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" })
return (
{greeting}, {name?.split(" ")[0] ?? "there"} 👋
{dateStr}
)
}
function OnboardingChecklist() {
const steps = [
{ label: "Add your first property", href: "/properties/new", icon: Building2 },
{ label: "Create a tenant profile", href: "/tenants/new", icon: TrendingUp },
{ label: "Record a rent payment", href: "/rent", icon: CreditCard },
{ label: "Set up a lease", href: "/leases/new", icon: CheckCircle2 },
]
return (
Welcome to Property Management Network!
Complete these steps to get started
{steps.map((step, i) => (
{i + 1}
{step.label}
))}
)
}
export default async function DashboardPage() {
const user = await getSessionUser()
if (!user) redirect("/login")
// Fetch profile for greeting
const profile = await db.query.profiles.findFirst({
where: eq(profiles.id, user.id),
columns: { full_name: true },
})
const [stats, recentPayments, openMaintenance, expiringLeases, monthlyRevenue, expenseBreakdown] = await Promise.all([
getDashboardStats(user.id),
getRecentRentPayments(user.id),
getOpenMaintenanceRequests(user.id),
getExpiringLeases(user.id),
getMonthlyRevenue(user.id),
getExpenseBreakdown(user.id),
])
const hasData = stats.totalProperties > 0
const rentTrendPct = stats.rentCollectedLastMonth > 0
? Math.round(((stats.rentCollectedThisMonth - stats.rentCollectedLastMonth) / stats.rentCollectedLastMonth) * 100)
: null
const occupancyColor: "default" | "success" | "warning" | "danger" =
stats.occupancyRate >= 80 ? "success" : stats.occupancyRate >= 50 ? "warning" : "danger"
return (
{/* Greeting */}
{/* Onboarding */}
{!hasData &&
}
{/* KPI Cards */}
0 ? Math.min(100, (stats.totalProperties / 10) * 100) : 0}
/>
0 ? `${formatCurrency(stats.rentOverdue)} overdue` : "No overdue rent"}
icon={Wrench}
variant={stats.openMaintenanceRequests > 0 ? "warning" : "default"}
/>
{/* Expiring leases alert */}
{expiringLeases.length > 0 && (
{expiringLeases.length} lease{expiringLeases.length > 1 ? "s" : ""} expiring soon
View all
{expiringLeases.slice(0, 4).map((lease: any) => {
const days = daysUntil(lease.lease_end)
return (
{lease.tenant?.first_name} {lease.tenant?.last_name}
{days <= 0 ? "Expired" : `${days}d`}
)
})}
)}
{/* Middle row: Revenue chart + Quick Actions */}
{/* Bottom row: Recent payments + Open maintenance */}
{/* Recent Payments */}
{recentPayments.length === 0 ? (
) : (
{recentPayments.map((payment: any) => (
{payment.tenant?.first_name?.[0]}{payment.tenant?.last_name?.[0]}
{payment.tenant?.first_name} {payment.tenant?.last_name}
{payment.property?.name} · {formatDate(payment.due_date)}
{formatCurrency(payment.amount)}
))}
)}
{/* Open Maintenance */}
Open Maintenance
{stats.openMaintenanceRequests > 0 && (
{stats.openMaintenanceRequests}
)}
View all
{openMaintenance.length === 0 ? (
) : (
{openMaintenance.map((req: any) => (
{req.title}
{req.property?.name}{req.tenant ? ` · ${req.tenant.first_name} ${req.tenant.last_name}` : ""}
))}
)}
)
}