Source: components/Map.tsx

'use client'
import React, { useCallback, useState } from 'react';
import { GoogleMap, Marker, useJsApiLoader} from '@react-google-maps/api';
import { Event } from '@/types/event';

const mapContainerStyle = {
    width: '100%',
    height: '100%'
};

// Map component props
interface MapProps {
    events: Event[];
}

const nightModeStyles = [
    { elementType: "geometry", stylers: [{ color: "#242f3e" }] },
    { elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
    { elementType: "labels.text.fill", stylers: [{ color: "#746855" }] },
    {
      featureType: "administrative.locality",
      elementType: "labels.text.fill",
      stylers: [{ color: "#d59563" }],
    },
    {
      featureType: "poi",
      elementType: "labels.text.fill",
      stylers: [{ color: "#d59563" }],
    },
    {
      featureType: "poi.park",
      elementType: "geometry",
      stylers: [{ color: "#263c3f" }],
    },
    {
      featureType: "poi.park",
      elementType: "labels.text.fill",
      stylers: [{ color: "#6b9a76" }],
    },
    {
      featureType: "road",
      elementType: "geometry",
      stylers: [{ color: "#38414e" }],
    },
    {
      featureType: "road",
      elementType: "geometry.stroke",
      stylers: [{ color: "#212a37" }],
    },
    {
      featureType: "road",
      elementType: "labels.text.fill",
      stylers: [{ color: "#9ca5b3" }],
    },
    {
      featureType: "road.highway",
      elementType: "geometry",
      stylers: [{ color: "#746855" }],
    },
    {
      featureType: "road.highway",
      elementType: "geometry.stroke",
      stylers: [{ color: "#1f2835" }],
    },
    {
      featureType: "road.highway",
      elementType: "labels.text.fill",
      stylers: [{ color: "#f3d19c" }],
    },
    {
      featureType: "transit",
      elementType: "geometry",
      stylers: [{ color: "#2f3948" }],
    },
    {
      featureType: "transit.station",
      elementType: "labels.text.fill",
      stylers: [{ color: "#d59563" }],
    },
    {
      featureType: "water",
      elementType: "geometry",
      stylers: [{ color: "#17263c" }],
    },
    {
      featureType: "water",
      elementType: "labels.text.fill",
      stylers: [{ color: "#515c6d" }],
    },
    {
      featureType: "water",
      elementType: "labels.text.stroke",
      stylers: [{ color: "#17263c" }],
    },
];

/**
 * Map component.
 * 
 * @param {MapProps} props Map component props.
 * @returns {JSX.Element} Map component.
 */
export default function Map({ events }: MapProps) {
    let geocoder: google.maps.Geocoder;
    const [geocodedEvents, setGeocodedEvents] = useState(events);

    /**
     * Geocode the events.
     * 
     * @returns {void}
     * @throws {Error} Geocoding failed for address.
     * @returns {Promise<Event[]>} The geocoded events.
     */
    const geocode = useCallback(() => {
        geocoder = new google.maps.Geocoder();

        // Geocode the events
        const geocodePromises: Promise<Event>[] = events.map(event => new Promise((resolve, reject) => {
            const address = `${event.address}, ${event.city}, ${event.state} ${event.zip}`;
            geocoder.geocode({ address: address }, (results, status) => {
                if (status === 'OK' && results !== null) {
                    event.latitude = results[0].geometry.location.lat().toString();
                    event.longitude = results[0].geometry.location.lng().toString();
                    resolve(event);
                } else {
                    reject(new Error(`Geocoding failed for address: ${event.address}`));
                }
            });
        }));
        // Set the geocoded events
        Promise.all(geocodePromises)
            .then(geocodedEvents => {
                setGeocodedEvents(geocodedEvents);
            })
            .catch(error => console.error(error));
    }, [events]);

    // Load the Google Maps API
    const { isLoaded } = useJsApiLoader({
        id: 'google-map-script',
        googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!,
    })
    
    return (
        <div className='w-full h-64 sm:h-96 md:h-128 lg:h-256'>
            {isLoaded && <GoogleMap options={{ styles: nightModeStyles }} mapContainerStyle={mapContainerStyle} center={
                {
                    lat: parseFloat(geocodedEvents[0].latitude) || 0,
                    lng: parseFloat(geocodedEvents[0].longitude) || 0
                }
            } zoom={4} onLoad={geocode}>
                {geocodedEvents.map(event => (
                    <Marker key={event._id} position={{ lat: parseFloat(event.latitude), lng: parseFloat(event.longitude) }} />
                ))}
            </GoogleMap>}
        </div>
    );
}