import { notFound, redirect } from "next/navigation" import { and, eq, desc } from "drizzle-orm" import { db } from "@/lib/db" import { tenants as tenantsTable, rent_payments, maintenance_requests, leases as leasesTable } from "@/lib/db/schema" import { getSessionUser } from "@/lib/session" import { getEffectiveOwnerId } from "@/lib/account" import Link from "next/link" import { formatCurrency, formatDate } from "@/lib/utils" import { RentStatusBadge } from "@/components/dashboard/rent-status-badge" import { MaintenanceStatusBadge, PriorityBadge } from "@/components/dashboard/maintenance-status-badge" import { Mail, Phone } from "lucide-react" import { CopyButton } from "@/components/shared/copy-button" import { SendReminderButton } from "@/components/shared/send-reminder-button" import { DeleteTenantButton } from "@/components/forms/delete-tenant-button" export default async function TenantDetailPage({ params }: { params: Promise<{ tenantId: string }> }) { const user = await getSessionUser() if (!user) redirect("/login") const ownerId = await getEffectiveOwnerId(user.id) const { tenantId } = await params const tenant = await db.query.tenants.findFirst({ where: and(eq(tenantsTable.id, tenantId), eq(tenantsTable.user_id, ownerId)), with: { unit: { columns: { unit_number: true, rent_amount: true, bedrooms: true, bathrooms: true } }, property: { columns: { name: true, address_line1: true, city: true, state: true } }, }, }) if (!tenant) notFound() const [payments, maintenanceRequests, leases] = await Promise.all([ db .select() .from(rent_payments) .where(and(eq(rent_payments.user_id, ownerId), eq(rent_payments.tenant_id, tenantId))) .orderBy(desc(rent_payments.due_date)) .limit(6), db .select() .from(maintenance_requests) .where(and(eq(maintenance_requests.user_id, ownerId), eq(maintenance_requests.tenant_id, tenantId))) .orderBy(desc(maintenance_requests.created_at)) .limit(5), db .select() .from(leasesTable) .where(and(eq(leasesTable.user_id, ownerId), eq(leasesTable.tenant_id, tenantId))) .orderBy(desc(leasesTable.created_at)) .limit(1), ]) const activeLease = leases?.[0] const portalUrl = `${process.env.NEXT_PUBLIC_APP_URL}/tenant-portal/${tenant.portal_token}` return (
No payments recorded.
) : ({formatDate(p.due_date)}
{p.paid_date &&Paid {formatDate(p.paid_date)}
}No maintenance requests.
) : ({r.title}
{formatDate(r.created_at)}
{tenant.property?.name}
{tenant.unit &&Unit {tenant.unit.unit_number} · {tenant.unit.bedrooms}bd/{tenant.unit.bathrooms}ba
} {tenant.unit?.rent_amount &&{formatCurrency(tenant.unit.rent_amount)}/mo
} {tenant.move_in_date &&Moved in {formatDate(tenant.move_in_date)}
}{formatDate(activeLease.lease_start)} → {formatDate(activeLease.lease_end)}
{activeLease.status}
Share this link with the tenant to submit maintenance requests.
{tenant.emergency_contact_name}
{tenant.emergency_contact_phone &&{tenant.emergency_contact_phone}
}