← 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,
});
}