"use client"; import { Box, Badge, Flex, Text } from "@chakra-ui/react"; import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet"; import L, { DivIcon, LatLngBoundsLiteral } from "leaflet"; import "leaflet/dist/leaflet.css"; import "leaflet.markercluster/dist/MarkerCluster.css"; import "leaflet.markercluster/dist/MarkerCluster.Default.css"; import MarkerClusterGroup from "react-leaflet-markercluster"; import { useEffect, useMemo } from "react"; export type Company = { id: string; name: string; industry: "Tech" | "Retail" | "Manufacturing" | "Food" | "Healthcare"; lat: number; lng: number; address?: string; }; type Props = { companies: Company[]; selectedId?: string | null; onSelect?: (id: string) => void; autoFit?: boolean; }; const industryEmoji: Record = { Tech: "💻", Retail: "🛒", Manufacturing: "🏭", Food: "🍽️", Healthcare: "🏥", }; const industryColor: Record = { Tech: "#3b82f6", Retail: "#f59e0b", Manufacturing: "#6b7280", Food: "#10b981", Healthcare: "#ef4444", }; function makeIcon(industry: Company["industry"], highlighted: boolean): DivIcon { const size = highlighted ? 40 : 32; const color = industryColor[industry]; const emoji = industryEmoji[industry]; const border = highlighted ? `3px solid ${color}` : `2px solid ${color}`; return L.divIcon({ className: "company-div-icon", html: `
${emoji}
`, iconSize: [size, size], iconAnchor: [size / 2, size / 2], popupAnchor: [0, -size / 2], }); } function FlyTo({ lat, lng }: { lat: number; lng: number }) { const map = useMap(); useEffect(() => { map.flyTo([lat, lng], Math.max(map.getZoom(), 13), { duration: 0.7 }); }, [lat, lng, map]); return null; } function FitBoundsOnData({ points }: { points: { lat: number; lng: number }[] }) { const map = useMap(); useEffect(() => { if (!points?.length) return; let bounds: LatLngBoundsLiteral = [ [points[0].lat, points[0].lng], [points[0].lat, points[0].lng], ]; for (const p of points) { bounds = L.latLngBounds(bounds).extend([p.lat, p.lng]) as any; } map.fitBounds(bounds, { padding: [30, 30] }); }, [points, map]); return null; } export default function CompanyMap({ companies, selectedId, onSelect, autoFit = true }: Props) { const selected = useMemo( () => companies.find((c) => c.id === selectedId), [companies, selectedId] ); const center = useMemo<[number, number]>(() => { if (!companies.length) return [46.0569, 14.5058]; // Ljubljana fallback const lat = companies.reduce((a, c) => a + c.lat, 0) / companies.length; const lng = companies.reduce((a, c) => a + c.lng, 0) / companies.length; return [lat, lng]; }, [companies]); return ( {companies.map((c) => ( onSelect?.(c.id), mouseover: (e) => e.target.openPopup(), }} > {c.name} {c.industry} {c.address && {c.address}} ))} {autoFit && companies.length > 0 && !selected && ( ({ lat, lng }))} /> )} {selected && } ); }