// routes/landlord/reminders/index.tsx import { define } from "../../../utils.ts"; import { page } from "fresh"; import { getLeasesByOwner } from "../../../services/leaseService.ts"; import { getPaymentTransactionsByOwner } from "../../../services/paymentService.ts"; import { createMessage } from "../../../services/messageService.ts"; import { Lease, PaymentTransaction } from "../../../db/interfaces.ts"; const LATE_FEE_AMOUNT = 50; function formatCurrency(value: number): string { return `$${value.toLocaleString()}`; } function getTransactionTimestamp(transaction: PaymentTransaction): number { return transaction.payment_date ?? transaction.created_on ?? 0; } function isLatePayment(transaction: PaymentTransaction): boolean { const date = new Date(getTransactionTimestamp(transaction)); return date.getUTCDate() > 5; } export const handler = define.handlers({ async GET(ctx) { const { user_id } = ctx.state.data; const url = new URL(ctx.req.url); const success = url.searchParams.get("success") === "true"; if (!user_id) { return new Response("", { status: 302, headers: { Location: "/auth/login" }, }); } try { const leases = await getLeasesByOwner(user_id); const transactions = await getPaymentTransactionsByOwner(user_id); return page({ leases, transactions, success, }); } catch (error) { console.error("Error loading reminders:", error); return page({ error: "Failed to load reminders", }); } }, async POST(ctx) { const { user_id } = ctx.state.data; if (!user_id) { return new Response("", { status: 302, headers: { Location: "/auth/login" }, }); } const formData = await ctx.req.formData(); const leaseId = (formData.get("lease_id") || "").toString(); const tenantId = (formData.get("tenant_id") || "").toString(); const amount = (formData.get("amount") || "").toString(); if (leaseId && tenantId) { await createMessage( leaseId, user_id, tenantId, "payment", "Payment Reminder", `A rent payment of ${amount} is past due. Please submit payment or contact us with questions.`, ); } return new Response("", { status: 302, headers: { Location: "/landlord/reminders?success=true" }, }); }, }); export default define.page(function LandlordReminders({ data }) { const { leases, transactions, success, error } = data as { leases: Lease[]; transactions: PaymentTransaction[]; success?: boolean; error?: string; }; const leaseMap = new Map(leases.map((lease) => [lease.id, lease])); const overdue = (transactions || []) .filter((transaction) => transaction.transaction_status !== "completed") .map((transaction) => { const lease = leaseMap.get(transaction.lease_id || ""); const lateFee = isLatePayment(transaction) ? LATE_FEE_AMOUNT : 0; return { ...transaction, lease, lateFee, }; }); return (

Payment Reminders

Send reminders to tenants with overdue rent

{success && (
Reminder sent to tenant.
)} {error && (
{error}
)}
{overdue.length > 0 ? ( overdue.map((transaction) => ( )) ) : ( )}
Property Amount Due Status Late Fee
{transaction.lease?.property_address || "Property"} {formatCurrency(transaction.amount || 0)} {transaction.transaction_status || "pending"} {transaction.lateFee ? formatCurrency(transaction.lateFee) : "-"} {transaction.lease?.tenant_id && (
)}
No overdue payments at the moment.
); });