← back to Homesonspec

apps/web/src/app/api/map/route.ts

58 lines

import { NextResponse } from "next/server";
import { prisma } from "@homesonspec/database";

export const dynamic = "force-dynamic";

/**
 * Compact marker feed for the robust map explorer. Returns every mappable,
 * published, non-demo home with the fields the client toggles on, using terse
 * keys + rounded coords to keep the payload lean (~12k points gzips small).
 * Filtering happens client-side so toggling is instant (no round-trips).
 */
export async function GET() {
  const homes = await prisma.inventoryHome.findMany({
    where: {
      status: "PUBLISHED",
      isDemo: false,
      freshness: { not: "INACTIVE" }, // Stage-3: deduped/retired records never surface
      lat: { not: null },
      lon: { not: null },
    },
    select: {
      id: true,
      lat: true,
      lon: true,
      price: true,
      beds: true,
      constructionStatus: true,
      city: true,
      state: true,
      builder: { select: { slug: true, name: true } },
    },
  });

  const builderMap = new Map<string, { slug: string; name: string; count: number }>();
  const markers = homes.map((h) => {
    const b = h.builder;
    const rec = builderMap.get(b.slug) ?? { slug: b.slug, name: b.name, count: 0 };
    rec.count += 1;
    builderMap.set(b.slug, rec);
    return {
      i: h.id,
      la: Math.round(Number(h.lat) * 1e5) / 1e5,
      lo: Math.round(Number(h.lon) * 1e5) / 1e5,
      p: h.price === null ? null : Number(h.price),
      b: h.beds, // beds (nullable)
      s: h.constructionStatus, // MOVE_IN_READY | UNDER_CONSTRUCTION | PLANNED
      bl: b.slug,
      c: h.city ? `${h.city}, ${h.state}` : h.state,
    };
  });

  return NextResponse.json({
    markers,
    builders: [...builderMap.values()].sort((a, b) => b.count - a.count),
    total: markers.length,
  });
}