// routes/landlord/dashboard/index.tsx import { define } from "../../../utils.ts"; import { getLandlordDashboardData, getPendingLeaseApprovals } from "../../../services/landlordService.ts"; import { DashboardTenantApplication } from "../../../services/tenantApplicationService.ts"; import { DashboardMaintenanceRequest } from "../../../services/maintenanceRequestService.ts"; import { DashboardMessage } from "../../../services/messageService.ts"; import { page } from "fresh"; import { SessionCookie } from "../../auth/callback.ts"; import { MakeNewDate } from "../../../helpers.ts"; // Flexible interface for dashboard data - allows any structure interface FlexibleDashboardData { // Core dashboard stats from LandlordDashboardData properties?: { total: number; id: string; address_1: string; city: string; state: string; rental_status: string; monthly_rent: number; bedrooms: number; bathrooms: number; available: number; occupied: number; draft: number; }[]; leases?: { active: number; draft: number; expired: number; }[]; applications?: { pending: number; total_this_month: number; title: string; }[]; payments?: { expected_this_month: number; received_this_month: number; overdue: number; }[]; // Additional UI properties with proper types from service layer tenantApplications?: DashboardTenantApplication[]; maintenanceRequests?: DashboardMaintenanceRequest[]; recentMessages?: DashboardMessage[]; monthlyRevenue?: number; pendingLeaseApprovals?: any[]; [key: string]: unknown; // Allow any additional properties } // Flexible interface for component data interface LandlordDashboardPageData { stateData?: SessionCookie; dashboardData?: FlexibleDashboardData; error?: string; [key: string]: unknown; // Allow additional properties with unknown type } interface LandlordDashboardProps { data: LandlordDashboardPageData; } export const handler = define.handlers({ async GET(ctx) { const stateData: SessionCookie = ctx.state.data; const { user_id } = stateData; if (!user_id) { return new Response("", { status: 302, headers: { Location: "/auth/login" }, }); } try { const dashboardData = await getLandlordDashboardData(user_id); const pendingApprovals = await getPendingLeaseApprovals(user_id); return page({ stateData, dashboardData: { ...dashboardData, pendingApprovals, }, }); } catch (error) { console.error("Error loading landlord dashboard:", error); return page({ stateData, error: "Failed to load dashboard data", }); } }, }); export default define.page( function LandlordDashboard({ data }: LandlordDashboardProps) { const { stateData: _stateData, dashboardData, error } = data; if (error) { return (

Dashboard Error

{error}

Return to Onboarding
); } const { properties, tenantApplications, maintenanceRequests, recentMessages, monthlyRevenue, pendingLeaseApprovals, } = dashboardData || {}; return (
{/* Header */}

Landlord Dashboard

Welcome back! Here's what's happening with your properties.

{/* Stats Overview */}
Total Properties
{properties?.length || 0}
Pending Applications
{tenantApplications?.filter((app) => app.status === "pending" ).length || 0}
Open Maintenance
{maintenanceRequests?.filter((req) => req.status === "open" ).length || 0}
Monthly Revenue
${monthlyRevenue?.toLocaleString() || "0"}
{/* Recent Properties */}

Your Properties

View all
{properties && properties.length > 0 ? ( properties.slice(0, 3).map((property) => (

{property.address_1}

{property.city}, {property.state}

{property.rental_status}

${property.monthly_rent}/mo

{property.bedrooms}bd/{property.bathrooms}ba

)) ) : (

No properties yet

Add your first property
)}
{/* Recent Messages */}

Recent Messages

View all
{recentMessages && recentMessages.length > 0 ? ( recentMessages.slice(0, 3).map((message) => (
{message.sender_name?.charAt(0) || "T"}

{message.sender_name || "Tenant"}

{message.subject}

{MakeNewDate( (message as DashboardMessage) .created_on as number, ) .toLocaleDateString()}

{!message.is_read && (
)}
)) ) : (

No messages yet

)}
{/* Pending Applications */}

Pending Applications

View all
{tenantApplications && tenantApplications.filter((app) => app.status === "pending" ).length > 0 ? ( tenantApplications.filter((app) => app.status === "pending" ).slice(0, 3).map((application) => (

{application.applicant_name}

{application.applicant_email}

Applied {application.submitted_on ? new Date(application.submitted_on) .toLocaleDateString() : "Unknown date"}

)) ) : (

No pending applications

)}
{/* Pending Lease Approvals */}

Pending Lease Approvals

View all
{pendingLeaseApprovals && pendingLeaseApprovals.length > 0 ? ( pendingLeaseApprovals.slice(0, 3).map((approval: any) => (

{approval.property?.title || approval.property_address || "Property"}

Tenant: {approval.tenant?.name || approval.tenant?.email || "Unknown"}

Requested {approval.approval_requested_at ? new Date(approval.approval_requested_at).toLocaleDateString() : "Unknown date"}

)) ) : (

No pending lease approvals

)}
{/* Maintenance Requests */}

Maintenance Requests

View all
{maintenanceRequests && maintenanceRequests.filter((req) => req.status === "open") .length > 0 ? ( maintenanceRequests.filter((req) => req.status === "open") .slice(0, 3).map((request) => (

{request.description}

Priority: {request.priority}

{request.created_on ? new Date(request.created_on) .toLocaleDateString() : "Unknown date"}

{request.status}
)) ) : (

No open maintenance requests

)}
); }, );