'use client' import React, { memo, useMemo, useState } from 'react' import { ComposableMap, Geographies, Geography } from 'react-simple-maps' import countries from 'i18n-iso-countries' import enLocale from 'i18n-iso-countries/langs/en.json' import { useTheme } from 'next-themes' countries.registerLocale(enLocale) const geoUrl = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json" interface WorldMapProps { data: Array<{ country: string; pageviews: number }> } const WorldMap = ({ data }: WorldMapProps) => { const { resolvedTheme } = useTheme() const [tooltipContent, setTooltipContent] = useState<{ content: string; x: number; y: number } | null>(null) const processedData = useMemo(() => { const map = new Map() let max = 0 data.forEach(item => { if (item.country === 'Unknown') return // API returns 2 letter code. Convert to numeric (3 digits string) const numericCode = countries.alpha2ToNumeric(item.country) if (numericCode) { map.set(numericCode, item.pageviews) if (item.pageviews > max) max = item.pageviews } }) return { map, max } }, [data]) // Plausible-like colors based on provided SVG snippet const isDark = resolvedTheme === 'dark' const defaultFill = isDark ? "#2d2d2d" : "#F2F2F2" // Approx gray-750 / gray-150 const defaultStroke = isDark ? "#171717" : "#FFFFFF" // gray-900 / white const brandOrange = "#FD5E0F" return (
{({ geographies }) => geographies .filter(geo => geo.id !== "010") // Remove Antarctica .map((geo) => { const id = String(geo.id).padStart(3, '0') const count = processedData.map.get(id) || 0 const fillColor = count > 0 ? brandOrange : defaultFill return ( { const { name } = geo.properties setTooltipContent({ content: `${name}: ${count} visitors`, x: evt.clientX, y: evt.clientY }) }} onMouseLeave={() => { setTooltipContent(null) }} onMouseMove={(evt) => { setTooltipContent(prev => prev ? { ...prev, x: evt.clientX, y: evt.clientY } : null) }} /> ) }) } {tooltipContent && (
{tooltipContent.content}
)}
) } export default memo(WorldMap)