foamking/lib/distance.ts
mikl0s 7d2bbae1c6 Initial implementation of Foam King Gulve price calculator
Features:
- Complete Next.js 16 app with TypeScript and Tailwind CSS
- Customer-facing price calculator form with validation
- Admin mode showing detailed price breakdowns
- Accurate price calculations matching business requirements
- Responsive design with custom shadcn/ui theme
- API endpoint for quote requests
- Danish postal code distance calculations
- Complete test coverage against documentation examples

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-10 14:27:28 +00:00

154 lines
No EOL
3.7 KiB
TypeScript

// Predefined distances from 4550 Asnæs to major postal codes (round trip in km)
// This is a simplified approach for MVP - can be replaced with actual API later
export const POSTAL_CODE_DISTANCES: Record<string, number> = {
// København (2000-2999)
"2000": 200, // København K
"2100": 206, // København Ø
"2200": 208, // København N
"2300": 200, // København S
"2400": 210, // København NV
"2450": 216, // København SV
"2500": 194, // Valby
"2600": 182, // Glostrup
"2700": 188, // Brønshøj
"2800": 162, // Lyngby
"2900": 154, // Hellerup
// Nordsjælland (3000-3999)
"3000": 138, // Helsingør
"3050": 132, // Humlebæk
"3100": 128, // Hornbæk
"3200": 110, // Helsinge
"3300": 92, // Frederiksværk
"3400": 112, // Hillerød
"3460": 144, // Birkerød
"3500": 116, // Værløse
"3600": 90, // Frederikssund
// Vestsjælland (4000-4999)
"4000": 66, // Roskilde
"4100": 56, // Ringsted
"4200": 86, // Slagelse
"4300": 32, // Holbæk
"4400": 20, // Kalundborg
"4500": 16, // Nykøbing Sjælland
"4550": 0, // Asnæs (hjemmebase)
"4600": 70, // Køge
"4700": 132, // Næstved
"4800": 216, // Nykøbing F
"4900": 256, // Nakskov
// Fyn (5000-5999)
"5000": 290, // Odense C
"5100": 330, // Odense C
"5200": 300, // Odense V
"5220": 296, // Odense SØ
"5250": 284, // Odense SV
"5260": 288, // Odense S
"5270": 292, // Odense N
"5500": 350, // Middelfart
"5600": 360, // Faaborg
"5700": 340, // Svendborg
"5800": 380, // Nyborg
"5900": 370, // Rudkøbing
}
// Default distances based on first two digits of postal code
const DEFAULT_DISTANCES: Record<string, number> = {
"20": 200, // København området
"21": 206,
"22": 208,
"23": 200,
"24": 210,
"25": 194,
"26": 182,
"27": 188,
"28": 162,
"29": 154,
"30": 138, // Nordsjælland
"31": 128,
"32": 110,
"33": 92,
"34": 112,
"35": 116,
"36": 90,
"40": 66, // Vestsjælland
"41": 56,
"42": 86,
"43": 32,
"44": 20,
"45": 16,
"46": 70,
"47": 132,
"48": 216, // Lolland-Falster
"49": 256,
"50": 290, // Fyn
"51": 330,
"52": 296,
"53": 310,
"54": 320,
"55": 350,
"56": 360,
"57": 340,
"58": 380,
"59": 370,
}
export function getDistance(postalCode: string): number {
// First check if we have an exact match
if (POSTAL_CODE_DISTANCES[postalCode]) {
return POSTAL_CODE_DISTANCES[postalCode]
}
// Otherwise use default based on first two digits
const prefix = postalCode.slice(0, 2)
if (DEFAULT_DISTANCES[prefix]) {
return DEFAULT_DISTANCES[prefix]
}
// If still no match, estimate based on region
const firstDigit = postalCode[0]
switch (firstDigit) {
case "2":
return 190 // København average
case "3":
return 110 // Nordsjælland average
case "4":
return 100 // Vestsjælland average
case "5":
return 320 // Fyn average
default:
return 200 // Default fallback
}
}
export function isInCoverageArea(postalCode: string): boolean {
const firstDigit = postalCode[0]
const postalNumber = parseInt(postalCode)
// Check main coverage areas
if (["2", "3", "4", "5"].includes(firstDigit)) {
// Special check for Lolland-Falster (4800-4899)
if (postalNumber >= 4800 && postalNumber <= 4899) {
return true
}
// Exclude other 4900+ areas
if (postalNumber >= 4900 && postalNumber < 5000) {
return false
}
return true
}
return false
}
export function validateDanishPostalCode(postalCode: string): boolean {
// Danish postal codes are 4 digits
if (!/^\d{4}$/.test(postalCode)) {
return false
}
// Valid ranges for Danish postal codes
const code = parseInt(postalCode)
return code >= 1000 && code <= 9999
}