foamking/app/api/distance/route.ts
mikl0s 3ebb63dc6c Add admin dashboard, authentication, step wizard, and quote management
Expand the calculator with a multi-step wizard flow, admin dashboard with
quote tracking, login/auth system, distance API integration, and history
page. Add new UI components (dialog, progress, select, slider, switch),
update pricing logic, and improve the overall design with new assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 20:59:11 +00:00

145 lines
3.9 KiB
TypeScript

import { NextResponse } from "next/server"
import { getDistance as getDistanceFromTable } from "@/lib/distance"
const OPENROUTE_API_KEY = process.env.OPENROUTE_API_KEY
const HOME_COORDINATES = { lat: 55.8089, lng: 11.4955 } // 4550 Asnæs
// Postal code prefix to city name for better geocoding
const POSTAL_TO_CITY: Record<string, string> = {
"1": "København",
"2": "København",
"30": "Helsingør",
"31": "Hornbæk",
"32": "Helsinge",
"33": "Frederiksværk",
"34": "Hillerød",
"35": "Værløse",
"36": "Frederikssund",
"40": "Roskilde",
"41": "Ringsted",
"42": "Slagelse",
"43": "Holbæk",
"44": "Kalundborg",
"45": "Nykøbing Sjælland",
"46": "Køge",
"47": "Næstved",
"48": "Nykøbing Falster",
"49": "Nakskov",
"50": "Odense",
"51": "Odense",
"52": "Odense",
"55": "Middelfart",
"56": "Faaborg",
"57": "Svendborg",
"58": "Nyborg",
}
function getCityFromPostalCode(postalCode: string): string {
// Try full prefix first (2 digits), then first digit
return (
POSTAL_TO_CITY[postalCode.slice(0, 2)] || POSTAL_TO_CITY[postalCode.slice(0, 1)] || "Denmark"
)
}
interface OpenRouteResponse {
features: {
geometry: {
coordinates: number[]
}
}[]
}
interface DirectionsResponse {
routes: {
summary: {
distance: number // meters
}
}[]
}
async function geocodeAddress(
address: string | null,
postalCode: string
): Promise<{ lat: number; lng: number } | null> {
if (!OPENROUTE_API_KEY) return null
try {
// Build search text from address and city (postal codes don't work well with OpenRouteService)
const city = getCityFromPostalCode(postalCode)
let searchText: string
if (address && address.trim()) {
searchText = `${address}, ${city}, Denmark`
} else {
searchText = `${city}, Denmark`
}
const url = `https://api.openrouteservice.org/geocode/search?api_key=${OPENROUTE_API_KEY}&text=${encodeURIComponent(searchText)}&boundary.country=DK&size=1`
const response = await fetch(url, { headers: { Accept: "application/json" } })
if (!response.ok) return null
const data: OpenRouteResponse = await response.json()
if (!data.features?.[0]?.geometry?.coordinates) return null
const [lng, lat] = data.features[0].geometry.coordinates
return { lat, lng }
} catch {
return null
}
}
async function getRouteDistance(
from: { lat: number; lng: number },
to: { lat: number; lng: number }
): Promise<number | null> {
if (!OPENROUTE_API_KEY) return null
try {
const url = `https://api.openrouteservice.org/v2/directions/driving-car?api_key=${OPENROUTE_API_KEY}&start=${from.lng},${from.lat}&end=${to.lng},${to.lat}`
const response = await fetch(url, { headers: { Accept: "application/geo+json" } })
if (!response.ok) return null
const data = await response.json()
const distance = data.features?.[0]?.properties?.summary?.distance
if (!distance) return null
// Convert meters to km and double for round trip
return Math.round((distance / 1000) * 2)
} catch {
return null
}
}
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const postalCode = searchParams.get("postalCode")
const address = searchParams.get("address")
if (!postalCode || !/^\d{4}$/.test(postalCode)) {
return NextResponse.json({ error: "Invalid postal code" }, { status: 400 })
}
// Try OpenRouteService first if API key is configured
if (OPENROUTE_API_KEY) {
const destination = await geocodeAddress(address, postalCode)
if (destination) {
const distance = await getRouteDistance(HOME_COORDINATES, destination)
if (distance !== null) {
return NextResponse.json({
distance,
source: "openrouteservice",
postalCode,
})
}
}
}
// Fall back to postal code table
const distance = getDistanceFromTable(postalCode)
return NextResponse.json({
distance,
source: "table",
postalCode,
})
}