import React, { useEffect, useMemo, useState } from 'react'; import { InfoWindow, Map, Marker, useMap } from '@vis.gl/react-google-maps'; import { Globe, Loader2, MapPin, Navigation, Phone, Star } from 'lucide-react'; import { listBusinesses, listBusinessesForJobs } from '../lib/database'; import { cleanMapOptions } from '../lib/map-styles'; import type { Business } from '../types'; import type { AppUser } from '../../shared/types'; import { Alert, Badge, EmptyState } from './ui'; interface MapViewProps { user: AppUser; jobIds?: string[] | null; } export function MapView({ user, jobIds }: MapViewProps) { const map = useMap(); const [businesses, setBusinesses] = useState([]); const [selected, setSelected] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const selectedJobCount = jobIds?.length ?? 0; useEffect(() => { const loadBusinesses = async () => { setLoading(true); setError(null); try { const nextBusinesses = selectedJobCount > 0 ? await listBusinessesForJobs(user.id, jobIds ?? []) : await listBusinesses(user.id); setBusinesses(nextBusinesses); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load map leads.'); } finally { setLoading(false); } }; void loadBusinesses(); }, [jobIds, selectedJobCount, user.id]); useEffect(() => { if (!selected) { return; } const stillExists = businesses.some((business) => business.id === selected.id); if (!stillExists) { setSelected(null); } }, [businesses, selected]); useEffect(() => { if (!map || businesses.length === 0) { return; } const bounds = new google.maps.LatLngBounds(); let hasCoords = false; businesses.forEach((business) => { if (typeof business.latitude === 'number' && typeof business.longitude === 'number') { bounds.extend({ lat: business.latitude, lng: business.longitude }); hasCoords = true; } }); if (!hasCoords) { return; } map.fitBounds(bounds, 50); if (businesses.length === 1) { map.setZoom(15); } }, [businesses, map]); const center = useMemo(() => { const validCoords = businesses.filter( (business) => typeof business.latitude === 'number' && typeof business.longitude === 'number', ); if (validCoords.length === 0) { return { lat: 37.42, lng: -122.08 }; } const lat = validCoords.reduce((sum, business) => sum + (business.latitude ?? 0), 0) / validCoords.length; const lng = validCoords.reduce((sum, business) => sum + (business.longitude ?? 0), 0) / validCoords.length; return { lat, lng }; }, [businesses]); if (loading) { return (
); } if (businesses.length === 0) { return (
0 ? 'The selected research jobs do not have saved map results yet. Try completed jobs or run the research again.' : 'No saved leads are available yet. Run a research job to populate the map.'} /> {error ? {error} : null}
); } return (
{error && ( {error} )} {businesses.map((business) => typeof business.latitude === 'number' && typeof business.longitude === 'number' ? ( setSelected(business)} icon={{ path: google.maps.SymbolPath.CIRCLE, fillColor: selected?.id === business.id ? '#059669' : '#10b981', fillOpacity: 1, strokeColor: selected?.id === business.id ? '#064e3b' : '#065f46', strokeWeight: 2, scale: selected?.id === business.id ? 8 : 7, }} /> ) : null, )} {selected && typeof selected.latitude === 'number' && typeof selected.longitude === 'number' && ( setSelected(null)}>

{selected.name}

{selected.address}
{selected.rating || 'N/A'} ({selected.reviewCount || 0})
{selected.category || 'Uncategorized'}
{selected.website && ( Website )} {selected.phone && ( Call )}
Get Directions
)}

Map Summary

Total Leads on Map {businesses.length}
Selected Lead {selected ? selected.name : 'None'}
{selectedJobCount > 0 && (

Filtering by Selection

{selectedJobCount === 1 ? '1 selected research job' : `${selectedJobCount} selected research jobs`}

)}
); }