feat: add admin statistics API endpoint and GeoMap component for scan visualization.

This commit is contained in:
Timo 2026-01-07 18:46:23 +01:00
parent 509e5a51a7
commit 57d6e3a449
2 changed files with 39 additions and 36 deletions

View File

@ -2,6 +2,8 @@ import { NextRequest, NextResponse } from 'next/server';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { db } from '@/lib/db'; import { db } from '@/lib/db';
export const dynamic = 'force-dynamic';
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
try { try {
// Check newsletter-admin cookie authentication // Check newsletter-admin cookie authentication

View File

@ -81,37 +81,37 @@ const countryNameToCode: Record<string, string> = {
}; };
// ISO Alpha-2 to ISO Alpha-3 mapping (for matching with TopoJSON) // ISO Alpha-2 to ISO Alpha-3 mapping (for matching with TopoJSON)
const alpha2ToAlpha3: Record<string, string> = { const alpha2ToNumeric: Record<string, string> = {
'US': 'USA', 'US': '840',
'DE': 'DEU', 'DE': '276',
'GB': 'GBR', 'GB': '826',
'FR': 'FRA', 'FR': '250',
'CA': 'CAN', 'CA': '124',
'AU': 'AUS', 'AU': '036',
'JP': 'JPN', 'JP': '392',
'CN': 'CHN', 'CN': '156',
'IN': 'IND', 'IN': '356',
'BR': 'BRA', 'BR': '076',
'ES': 'ESP', 'ES': '724',
'IT': 'ITA', 'IT': '380',
'NL': 'NLD', 'NL': '528',
'CH': 'CHE', 'CH': '756',
'AT': 'AUT', 'AT': '040',
'PL': 'POL', 'PL': '616',
'SE': 'SWE', 'SE': '752',
'NO': 'NOR', 'NO': '578',
'DK': 'DNK', 'DK': '208',
'FI': 'FIN', 'FI': '246',
'BE': 'BEL', 'BE': '056',
'PT': 'PRT', 'PT': '620',
'IE': 'IRL', 'IE': '372',
'MX': 'MEX', 'MX': '484',
'AR': 'ARG', 'AR': '032',
'KR': 'KOR', 'KR': '410',
'SG': 'SGP', 'SG': '702',
'NZ': 'NZL', 'NZ': '554',
'RU': 'RUS', 'RU': '643',
'ZA': 'ZAF', 'ZA': '710',
}; };
interface CountryStat { interface CountryStat {
@ -132,9 +132,9 @@ const GeoMap: React.FC<GeoMapProps> = ({ countryStats, totalScans }) => {
countryStats.forEach((stat) => { countryStats.forEach((stat) => {
const alpha2 = countryNameToCode[stat.country] || stat.country; const alpha2 = countryNameToCode[stat.country] || stat.country;
const alpha3 = alpha2ToAlpha3[alpha2]; const numericCode = alpha2ToNumeric[alpha2];
if (alpha3) { if (numericCode) {
countryData[alpha3] = stat.count; countryData[numericCode] = stat.count;
if (stat.count > maxCount) maxCount = stat.count; if (stat.count > maxCount) maxCount = stat.count;
} }
}); });
@ -158,8 +158,9 @@ const GeoMap: React.FC<GeoMapProps> = ({ countryStats, totalScans }) => {
<Geographies geography={geoUrl}> <Geographies geography={geoUrl}>
{({ geographies }) => {({ geographies }) =>
geographies.map((geo) => { geographies.map((geo) => {
const isoCode = geo.properties.ISO_A3 || geo.id; // geo.id is the numeric ISO code as a string (e.g., "840" for US)
const scanCount = countryData[isoCode] || 0; const geoId = geo.id;
const scanCount = countryData[geoId] || 0;
const fillColor = scanCount > 0 ? colorScale(scanCount) : '#F1F5F9'; const fillColor = scanCount > 0 ? colorScale(scanCount) : '#F1F5F9';
return ( return (