// apps/<app>/src/components/MapComponent.tsx
import { useEffect, useRef, useState } from 'react';
import { Loader } from '@googlemaps/js-api-loader';
export default function MapComponent() {
const mapRef = useRef<HTMLDivElement>(null);
const mapInstanceRef = useRef<google.maps.Map | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string>();
const apiKey = import.meta.env.VITE_GOOGLEMAPS_API_KEY;
useEffect(() => {
if (!apiKey) {
setIsLoading(false);
setError('Google Maps not connected. Connect it from the app\'s Integrations button.');
return;
}
if (mapInstanceRef.current) { setIsLoading(false); return; }
let mounted = true;
const loader = new Loader({ apiKey, version: 'weekly' });
loader.importLibrary('maps').then(({ Map }) => {
if (!mounted || !mapRef.current || mapInstanceRef.current) return;
mapInstanceRef.current = new Map(mapRef.current, {
center: { lat: 37.7749, lng: -122.4194 },
zoom: 12,
});
setIsLoading(false);
}).catch((err) => {
if (mounted) { setIsLoading(false); setError('Failed to load Google Maps'); console.error(err); }
});
return () => { mounted = false; };
}, [apiKey]);
// Always render the map container; overlay loading/error on top of it.
return (
<div className="relative w-full h-[400px]">
<div ref={mapRef} className="w-full h-full" />
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-background/80 text-muted-foreground">
Loading map…
</div>
)}
{error && (
<div className="absolute inset-0 flex items-center justify-center bg-background p-4 text-destructive">
{error}
</div>
)}
</div>
);
}