This commit is contained in:
root
2025-12-22 06:43:19 +01:00
parent a940d51475
commit 6f4ca75faf
25 changed files with 1350 additions and 221 deletions

92
lib/geolocation.ts Normal file
View File

@@ -0,0 +1,92 @@
import { NextRequest } from 'next/server'
import { CHF_COUNTRIES } from '@/lib/currency'
/**
* Get client IP address from request headers
*/
function getClientIp(request: NextRequest): string | null {
// Check various headers that might contain the real IP
const forwardedFor = request.headers.get('x-forwarded-for')
if (forwardedFor) {
// x-forwarded-for can contain multiple IPs, take the first one
return forwardedFor.split(',')[0].trim()
}
const realIp = request.headers.get('x-real-ip')
if (realIp) {
return realIp.trim()
}
const cfConnectingIp = request.headers.get('cf-connecting-ip') // Cloudflare
if (cfConnectingIp) {
return cfConnectingIp.trim()
}
// Fallback to remote address if available
const remoteAddress = request.headers.get('remote-addr')
if (remoteAddress) {
return remoteAddress.trim()
}
return null
}
/**
* Get country code from IP address using ip-api.com (free, no API key required)
* Returns country code (e.g., 'CH' for Switzerland, 'SG' for Singapore), or null if detection fails
*/
export async function getCountryFromIp(request: NextRequest): Promise<string | null> {
try {
const ip = getClientIp(request)
if (!ip) {
console.warn('Could not determine client IP')
return null
}
// Skip localhost/private IPs
if (ip === '127.0.0.1' || ip === '::1' || ip.startsWith('192.168.') || ip.startsWith('10.') || ip.startsWith('172.')) {
// For local development, default to Switzerland
return 'CH'
}
// Use ip-api.com free service (no API key required, rate limited)
// Returns JSON with country code
const response = await fetch(`http://ip-api.com/json/${ip}?fields=countryCode`, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
})
if (!response.ok) {
console.warn(`Failed to fetch geolocation: ${response.status}`)
return null
}
const data = await response.json()
if (data.countryCode) {
return data.countryCode
}
return null
} catch (error) {
console.error('Error detecting country from IP:', error)
return null
}
}
/**
* Calculate shipping fee based on country
* Returns shipping fee in the appropriate currency
* 15 CHF for countries in CHF_COUNTRIES, 40 EUR for all other countries
*/
export function calculateShippingFee(countryCode: string | null): number {
// 15 CHF for countries in CHF_COUNTRIES, 40 EUR for all other countries
if (countryCode && CHF_COUNTRIES.includes(countryCode as any)) {
return 15
}
return 40
}