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 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" export default async function TenantDetailPage({ params }: { params: Promise<{ tenantId: string }> }) { const user = await getSessionUser() if (!user) redirect("/login") const { tenantId } = await params const tenant = await db.query.tenants.findFirst({ where: and(eq(tenantsTable.id, tenantId), eq(tenantsTable.user_id, user.id)), 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, user.id), 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, user.id), eq(maintenance_requests.tenant_id, tenantId))) .orderBy(desc(maintenance_requests.created_at)) .limit(5), db .select() .from(leasesTable) .where(and(eq(leasesTable.user_id, user.id), 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 (
{/* Breadcrumb */}
Tenants / {tenant.first_name} {tenant.last_name}
{/* Header */}
{tenant.first_name[0]}{tenant.last_name[0]}

{tenant.first_name} {tenant.last_name}

{tenant.email && {tenant.email}} {tenant.phone && {tenant.phone}}
Edit
{/* Rent payments */}

Rent Payments

+ Record
{!payments?.length ? (

No payments recorded.

) : (
{payments.map((p: any) => (

{formatDate(p.due_date)}

{p.paid_date &&

Paid {formatDate(p.paid_date)}

}
{formatCurrency(p.amount)} {(p.status === "pending" || p.status === "overdue") && tenant.email && ( )}
))}
)}
{/* Maintenance */}

Maintenance Requests

+ New
{!maintenanceRequests?.length ? (

No maintenance requests.

) : (
{maintenanceRequests.map((r: any) => (

{r.title}

{formatDate(r.created_at)}

))}
)}
{/* Sidebar */}
{/* Unit info */}

Unit

{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)}

}
{/* Active lease */} {activeLease && (

Lease

{formatDate(activeLease.lease_start)} → {formatDate(activeLease.lease_end)}

{activeLease.status}

)} {/* Tenant portal */}

Tenant Portal

Share this link with the tenant to submit maintenance requests.

/tenant-portal/{tenant.portal_token?.slice(0, 12)}… Open
{/* Emergency contact */} {tenant.emergency_contact_name && (

Emergency Contact

{tenant.emergency_contact_name}

{tenant.emergency_contact_phone &&

{tenant.emergency_contact_phone}

}
)}
) }