/* eslint-disable @typescript-eslint/no-explicit-any */ "use server" import { eq } from "drizzle-orm" import { db } from "@/lib/db" import { properties, units, tenants, leases, rent_payments, maintenance_requests, expenses, profiles, } from "@/lib/db/schema" import { getSessionUser } from "@/lib/session" import { redirect } from "next/navigation" export async function seedDemoData() { if (process.env.NODE_ENV === "production") { throw new Error("Demo tools are disabled in production") } const user = await getSessionUser() if (!user) redirect("/login") const uid = user.id // ── 1. Properties ────────────────────────────────────────────── const props = await db .insert(properties) .values([ { user_id: uid, name: "Maple Court Apartments", address_line1: "14 Maple Street", city: "Austin", state: "TX", postal_code: "78701", property_type: "residential", total_units: 3, notes: "3-storey walkup, built 2005", }, { user_id: uid, name: "Riverdale Flats", address_line1: "87 Riverside Drive", city: "Austin", state: "TX", postal_code: "78702", property_type: "residential", total_units: 2, notes: "2 ground-floor units", }, { user_id: uid, name: "Crestwood Villa", address_line1: "220 Crestwood Lane", city: "Austin", state: "TX", postal_code: "78703", property_type: "residential", total_units: 2, notes: "Detached villa with garden units", }, ]) .returning({ id: properties.id, name: properties.name }) const [maple, river, crest] = props // ── 2. Units ─────────────────────────────────────────────────── const unitRows = await db .insert(units) .values([ // Maple Court — 3 units { user_id: uid, property_id: maple.id, unit_number: "1A", bedrooms: 2, bathrooms: 1, sq_ft: 850, rent_amount: 1800, status: "occupied" }, { user_id: uid, property_id: maple.id, unit_number: "1B", bedrooms: 1, bathrooms: 1, sq_ft: 620, rent_amount: 1350, status: "occupied" }, { user_id: uid, property_id: maple.id, unit_number: "2A", bedrooms: 3, bathrooms: 2, sq_ft: 1100, rent_amount: 2400, status: "occupied" }, // Riverdale — 2 units { user_id: uid, property_id: river.id, unit_number: "G1", bedrooms: 2, bathrooms: 1, sq_ft: 780, rent_amount: 1650, status: "occupied" }, { user_id: uid, property_id: river.id, unit_number: "G2", bedrooms: 1, bathrooms: 1, sq_ft: 560, rent_amount: 1200, status: "vacant" }, // Crestwood — 2 units { user_id: uid, property_id: crest.id, unit_number: "A", bedrooms: 3, bathrooms: 2, sq_ft: 1250, rent_amount: 2800, status: "occupied" }, { user_id: uid, property_id: crest.id, unit_number: "B", bedrooms: 2, bathrooms: 1, sq_ft: 900, rent_amount: 2100, status: "occupied" }, ]) .returning({ id: units.id, unit_number: units.unit_number, property_id: units.property_id, rent_amount: units.rent_amount }) const [u1A, u1B, u2A, uG1, , uA, uB] = unitRows // ── 3. Tenants ───────────────────────────────────────────────── const tenantRows = await db .insert(tenants) .values([ { user_id: uid, property_id: maple.id, unit_id: u1A.id, first_name: "Sarah", last_name: "Johnson", email: "sarah.johnson@email.com", phone: "+1 (512) 555-0101", move_in_date: "2023-06-01", status: "active", emergency_contact_name: "Mike Johnson", emergency_contact_phone: "+1 (512) 555-0102", }, { user_id: uid, property_id: maple.id, unit_id: u1B.id, first_name: "Marcus", last_name: "Lee", email: "marcus.lee@email.com", phone: "+1 (512) 555-0201", move_in_date: "2023-09-01", status: "active", emergency_contact_name: "Lisa Lee", emergency_contact_phone: "+1 (512) 555-0202", }, { user_id: uid, property_id: maple.id, unit_id: u2A.id, first_name: "Priya", last_name: "Patel", email: "priya.patel@email.com", phone: "+1 (512) 555-0301", move_in_date: "2022-12-01", status: "active", emergency_contact_name: "Raj Patel", emergency_contact_phone: "+1 (512) 555-0302", }, { user_id: uid, property_id: river.id, unit_id: uG1.id, first_name: "David", last_name: "Kim", email: "david.kim@email.com", phone: "+1 (512) 555-0401", move_in_date: "2024-01-15", status: "active", emergency_contact_name: "Jenny Kim", emergency_contact_phone: "+1 (512) 555-0402", }, { user_id: uid, property_id: crest.id, unit_id: uA.id, first_name: "Emily", last_name: "Carter", email: "emily.carter@email.com", phone: "+1 (512) 555-0501", move_in_date: "2023-03-01", status: "active", emergency_contact_name: "Tom Carter", emergency_contact_phone: "+1 (512) 555-0502", }, { user_id: uid, property_id: crest.id, unit_id: uB.id, first_name: "James", last_name: "Williams", email: "james.williams@email.com", phone: "+1 (512) 555-0601", move_in_date: "2024-03-01", status: "active", emergency_contact_name: "Anna Williams", emergency_contact_phone: "+1 (512) 555-0602", }, ]) .returning({ id: tenants.id, first_name: tenants.first_name, last_name: tenants.last_name, property_id: tenants.property_id, unit_id: tenants.unit_id }) const [tSarah, tMarcus, tPriya, tDavid, tEmily, tJames] = tenantRows // Update units with current_tenant_id await Promise.all([ db.update(units).set({ current_tenant_id: tSarah.id }).where(eq(units.id, u1A.id)), db.update(units).set({ current_tenant_id: tMarcus.id }).where(eq(units.id, u1B.id)), db.update(units).set({ current_tenant_id: tPriya.id }).where(eq(units.id, u2A.id)), db.update(units).set({ current_tenant_id: tDavid.id }).where(eq(units.id, uG1.id)), db.update(units).set({ current_tenant_id: tEmily.id }).where(eq(units.id, uA.id)), db.update(units).set({ current_tenant_id: tJames.id }).where(eq(units.id, uB.id)), ]) // ── 4. Leases ────────────────────────────────────────────────── await db.insert(leases).values([ { user_id: uid, tenant_id: tSarah.id, property_id: maple.id, unit_id: u1A.id, lease_start: "2023-06-01", lease_end: "2025-05-31", rent_amount: 1800, security_deposit: 3600, lease_type: "fixed", status: "active", }, { user_id: uid, tenant_id: tMarcus.id, property_id: maple.id, unit_id: u1B.id, lease_start: "2023-09-01", lease_end: "2025-08-31", rent_amount: 1350, security_deposit: 2700, lease_type: "fixed", status: "active", }, { user_id: uid, tenant_id: tPriya.id, property_id: maple.id, unit_id: u2A.id, lease_start: "2022-12-01", lease_end: "2025-05-15", // expiring soon! rent_amount: 2400, security_deposit: 4800, lease_type: "fixed", status: "active", }, { user_id: uid, tenant_id: tDavid.id, property_id: river.id, unit_id: uG1.id, lease_start: "2024-01-15", lease_end: "2026-01-14", rent_amount: 1650, security_deposit: 3300, lease_type: "fixed", status: "active", }, { user_id: uid, tenant_id: tEmily.id, property_id: crest.id, unit_id: uA.id, lease_start: "2023-03-01", lease_end: "2025-04-28", // expiring very soon! rent_amount: 2800, security_deposit: 5600, lease_type: "fixed", status: "active", }, { user_id: uid, tenant_id: tJames.id, property_id: crest.id, unit_id: uB.id, lease_start: "2024-03-01", lease_end: "2026-02-28", rent_amount: 2100, security_deposit: 4200, lease_type: "fixed", status: "active", }, ]) // ── 5. Rent Payments (last 6 months) ────────────────────────── const now = new Date() function dueDate(monthsAgo: number, day = 1) { const d = new Date(now.getFullYear(), now.getMonth() - monthsAgo, day) return d.toISOString().slice(0, 10) } function paidDate(monthsAgo: number, day = 3) { const d = new Date(now.getFullYear(), now.getMonth() - monthsAgo, day) return d.toISOString().slice(0, 10) } const paymentRows: (typeof rent_payments.$inferInsert)[] = [] // Sarah — always pays on time (all paid) for (let m = 5; m >= 1; m--) { paymentRows.push({ user_id: uid, tenant_id: tSarah.id, property_id: maple.id, unit_id: u1A.id, amount: 1800, due_date: dueDate(m), paid_date: paidDate(m), status: "paid", payment_method: "bank_transfer", }) } // Sarah — this month pending paymentRows.push({ user_id: uid, tenant_id: tSarah.id, property_id: maple.id, unit_id: u1A.id, amount: 1800, due_date: dueDate(0), status: "pending", }) // Marcus — mostly paid, one overdue for (let m = 5; m >= 2; m--) { paymentRows.push({ user_id: uid, tenant_id: tMarcus.id, property_id: maple.id, unit_id: u1B.id, amount: 1350, due_date: dueDate(m), paid_date: paidDate(m), status: "paid", payment_method: "card", }) } paymentRows.push({ user_id: uid, tenant_id: tMarcus.id, property_id: maple.id, unit_id: u1B.id, amount: 1350, due_date: dueDate(1), status: "overdue", }) paymentRows.push({ user_id: uid, tenant_id: tMarcus.id, property_id: maple.id, unit_id: u1B.id, amount: 1350, due_date: dueDate(0), status: "pending", }) // Priya — all paid on time for (let m = 5; m >= 1; m--) { paymentRows.push({ user_id: uid, tenant_id: tPriya.id, property_id: maple.id, unit_id: u2A.id, amount: 2400, due_date: dueDate(m), paid_date: paidDate(m, 2), status: "paid", payment_method: "stripe", }) } paymentRows.push({ user_id: uid, tenant_id: tPriya.id, property_id: maple.id, unit_id: u2A.id, amount: 2400, due_date: dueDate(0), status: "pending", }) // David — started Jan 2024, 3 paid months for (let m = 3; m >= 1; m--) { paymentRows.push({ user_id: uid, tenant_id: tDavid.id, property_id: river.id, unit_id: uG1.id, amount: 1650, due_date: dueDate(m), paid_date: paidDate(m), status: "paid", payment_method: "bank_transfer", }) } paymentRows.push({ user_id: uid, tenant_id: tDavid.id, property_id: river.id, unit_id: uG1.id, amount: 1650, due_date: dueDate(0), status: "pending", }) // Emily — 4 paid for (let m = 5; m >= 2; m--) { paymentRows.push({ user_id: uid, tenant_id: tEmily.id, property_id: crest.id, unit_id: uA.id, amount: 2800, due_date: dueDate(m), paid_date: paidDate(m), status: "paid", payment_method: "stripe", }) } paymentRows.push({ user_id: uid, tenant_id: tEmily.id, property_id: crest.id, unit_id: uA.id, amount: 2800, due_date: dueDate(1), status: "overdue", }) paymentRows.push({ user_id: uid, tenant_id: tEmily.id, property_id: crest.id, unit_id: uA.id, amount: 2800, due_date: dueDate(0), status: "pending", }) // James — new tenant, 2 paid for (let m = 2; m >= 1; m--) { paymentRows.push({ user_id: uid, tenant_id: tJames.id, property_id: crest.id, unit_id: uB.id, amount: 2100, due_date: dueDate(m), paid_date: paidDate(m), status: "paid", payment_method: "card", }) } paymentRows.push({ user_id: uid, tenant_id: tJames.id, property_id: crest.id, unit_id: uB.id, amount: 2100, due_date: dueDate(0), status: "pending", }) await db.insert(rent_payments).values(paymentRows) // ── 6. Maintenance Requests ──────────────────────────────────── const twoWeeksAgo = new Date(now); twoWeeksAgo.setDate(now.getDate() - 14) const oneWeekAgo = new Date(now); oneWeekAgo.setDate(now.getDate() - 7) const yesterday = new Date(now); yesterday.setDate(now.getDate() - 1) const threeDaysAgo = new Date(now); threeDaysAgo.setDate(now.getDate() - 3) await db.insert(maintenance_requests).values([ { user_id: uid, tenant_id: tSarah.id, property_id: maple.id, unit_id: u1A.id, title: "Leaking kitchen faucet", description: "The kitchen faucet has been dripping constantly for the past week. Water is pooling under the sink cabinet.", category: "plumbing", priority: "medium", status: "open", created_at: oneWeekAgo.toISOString(), }, { user_id: uid, tenant_id: tMarcus.id, property_id: maple.id, unit_id: u1B.id, title: "Heating unit not working", description: "The wall heater in the bedroom has stopped working completely. It's getting cold at night.", category: "hvac", priority: "high", status: "in_progress", assigned_to: "HVAC Pro Services", estimated_cost: 350, created_at: twoWeeksAgo.toISOString(), }, { user_id: uid, tenant_id: tPriya.id, property_id: maple.id, unit_id: u2A.id, title: "Broken window latch — Unit 2A", description: "The latch on the living room window is broken. Window won't close fully and is a security concern.", category: "general", priority: "medium", status: "open", created_at: threeDaysAgo.toISOString(), }, { user_id: uid, tenant_id: tEmily.id, property_id: crest.id, unit_id: uA.id, title: "Garage door motor failure", description: "The automatic garage door opener stopped working. The motor makes a clicking noise but door won't lift.", category: "electrical", priority: "high", status: "open", created_at: yesterday.toISOString(), }, { user_id: uid, tenant_id: tDavid.id, property_id: river.id, unit_id: uG1.id, title: "Paint peeling in bathroom", description: "Bathroom ceiling paint is bubbling and peeling near the shower area. Likely moisture issue.", category: "general", priority: "low", status: "resolved", assigned_to: "Quick Fix Painters", actual_cost: 180, resolved_at: twoWeeksAgo.toISOString(), resolution_notes: "Repainted bathroom ceiling with moisture-resistant paint.", created_at: new Date(now.getFullYear(), now.getMonth() - 2, 10).toISOString(), }, { user_id: uid, tenant_id: tJames.id, property_id: crest.id, unit_id: uB.id, title: "Kitchen exhaust fan noisy", description: "The kitchen exhaust fan makes a loud rattling noise. Sounds like something is loose inside.", category: "general", priority: "low", status: "open", created_at: new Date(now.getFullYear(), now.getMonth(), 5).toISOString(), }, ]) // ── 7. Expenses ──────────────────────────────────────────────── await db.insert(expenses).values([ { user_id: uid, property_id: maple.id, unit_id: u1B.id, category: "repairs", description: "HVAC inspection and repair — Unit 1B", amount: 320, expense_date: twoWeeksAgo.toISOString().slice(0, 10), vendor: "HVAC Pro Services", is_recurring: false, }, { user_id: uid, property_id: maple.id, category: "management", description: "Common area deep clean — Maple Court", amount: 250, expense_date: new Date(now.getFullYear(), now.getMonth(), 8).toISOString().slice(0, 10), vendor: "CleanPro Austin", is_recurring: true, recurrence: "monthly", }, { user_id: uid, property_id: river.id, category: "insurance", description: "Building insurance premium — Riverdale Flats", amount: 1200, expense_date: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString().slice(0, 10), vendor: "State Farm", is_recurring: true, recurrence: "annual", }, { user_id: uid, property_id: crest.id, unit_id: uA.id, category: "repairs", description: "Garage door motor replacement", amount: 480, expense_date: new Date(now.getFullYear(), now.getMonth(), 12).toISOString().slice(0, 10), vendor: "Austin Door Co.", is_recurring: false, }, { user_id: uid, property_id: maple.id, category: "utilities", description: "Common area electricity — March", amount: 145, expense_date: new Date(now.getFullYear(), now.getMonth() - 1, 28).toISOString().slice(0, 10), vendor: "Austin Energy", is_recurring: true, recurrence: "monthly", }, { user_id: uid, property_id: maple.id, category: "management", description: "Property management software subscription", amount: 29, expense_date: new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10), vendor: "Property Management Network", is_recurring: true, recurrence: "monthly", }, { user_id: uid, property_id: crest.id, category: "management", description: "Garden landscaping — quarterly", amount: 360, expense_date: new Date(now.getFullYear(), now.getMonth() - 2, 15).toISOString().slice(0, 10), vendor: "Green Thumb Landscaping", is_recurring: true, recurrence: "quarterly", }, { user_id: uid, property_id: river.id, category: "taxes", description: "Property tax Q1 payment", amount: 2100, expense_date: new Date(now.getFullYear(), now.getMonth() - 3, 15).toISOString().slice(0, 10), vendor: "Travis County Tax Office", is_recurring: true, recurrence: "quarterly", }, ]) redirect("/dashboard") } export async function setTestPlan(plan: "pro" | "landlord" | "lifetime" | "starter") { if (process.env.NODE_ENV === "production") { throw new Error("Demo tools are disabled in production") } const user = await getSessionUser() if (!user) redirect("/login") await db.update(profiles).set({ plan }).where(eq(profiles.id, user.id)) redirect("/settings/demo") } export async function clearDemoData() { if (process.env.NODE_ENV === "production") { throw new Error("Demo tools are disabled in production") } const user = await getSessionUser() if (!user) redirect("/login") const uid = user.id // Delete in dependency order await db.delete(expenses).where(eq(expenses.user_id, uid)) await db.delete(maintenance_requests).where(eq(maintenance_requests.user_id, uid)) await db.delete(rent_payments).where(eq(rent_payments.user_id, uid)) await db.delete(leases).where(eq(leases.user_id, uid)) await db.delete(tenants).where(eq(tenants.user_id, uid)) await db.delete(units).where(eq(units.user_id, uid)) await db.delete(properties).where(eq(properties.user_id, uid)) redirect("/dashboard") }