Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with markers on Google Maps API - not always loading #145

Open
anafaria-slefty opened this issue Dec 12, 2023 · 0 comments
Open

Issues with markers on Google Maps API - not always loading #145

anafaria-slefty opened this issue Dec 12, 2023 · 0 comments

Comments

@anafaria-slefty
Copy link

I'm working on a website with Google Maps API, particularly with @ubilabs/google-maps-react-hooks.
I'm not very experienced so I'm having some difficulties understanding why there's an issue.
When I load the website (either locally or online) the markers don't always show up. It could be on loading the site at first or when I refresh, they disappear and reapper upon new refreshing of the page. This never happens if I have my developer tools open (docked or undocked) and I can't figure out why! I've been trying for days.

index.txs

import { GoogleMapsProvider } from '@ubilabs/google-maps-react-hooks';
import React, { useState, useEffect, useCallback} from 'react';
import { useGeoReportState } from '../../context/GeoReportContext';
import { useMapContext, useMapDispatch } from '../../context/MapContext';
import { options } from './MapElements';
import TestMap from './TestMap';

const Index = () => {
	const [mapContainer, setMapContainer] = useState<HTMLDivElement | null>(null);

	const mapDispatch = useMapDispatch();
	const mapState = useMapContext();
	const reportState = useGeoReportState();
	// eslint-disable-next-line @typescript-eslint/no-explicit-any
	const onLoad = useCallback((map: any) => {
		mapDispatch.setMap(map);
        google.maps.event.trigger(map, 'resize');
	}, [reportState]);
	return (
        <>
		<div className='flex flex-col w-full h-full'>
			<GoogleMapsProvider
				mapOptions={options(mapState)}
				googleMapsAPIKey={process.env.REACT_APP_API_KEY as string}
				mapContainer={mapContainer}
				version='beta'
				onLoadMap={onLoad}
				libraries={['places']}
			>
				<TestMap />
				<div ref={(node) => setMapContainer(node)} style={{ height: '100vh' }} />
			</GoogleMapsProvider>
		</div> 


    </>
	);
};

export default Index;

TestMap.tsx

import React, { useState, useEffect, SetStateAction } from 'react';
import { useGeoReportState } from '../../context/GeoReportContext';
import { useMapContext } from '../../context/MapContext';
import { findMode, formSubmitGeoCoder, getSoilTypeColor } from '../../utils/Util';
import Navbar from '../Navbar';
import { notificationHandler, surveyLengthHandler } from '../../utils/ContextHandlers';
import { MarkerClusterer, SuperClusterAlgorithm } from '@googlemaps/markerclusterer';
import Icon from '../../img/point.png';
import FileSubmit from '../Form/FileSubmit';
import Form from '../Form/Form';
import ThankYou from '../Form/ThankYou';
import { IconContext } from 'react-icons';
import { AiOutlineLeft, AiOutlineRight, AiOutlineReload } from 'react-icons/ai';
import { GeoReport, Survey } from '../../types/GeoReportTypes';
import { SurveyData } from '../../types/SurveyTypes';
import { useNotificationDispatch } from '../../context/NotificationContext';
import { useSurveyDispatch } from '../../context/SurveyContext';
import PointData from '../Form/PointData';
import { useGoogleMap } from '@ubilabs/google-maps-react-hooks';

const TestMap: React.FC = () => {

	const geoReportState = useGeoReportState();
	const notificationDispatch = useNotificationDispatch();
	const mapState = useMapContext();
	const surveyDispatch = useSurveyDispatch();
	const map = useGoogleMap();

	let formData = {};

	const [showFileSubmit, setShowFileSubmit] = useState(false);
	const [showSliderForms, showSlider] = useState(false);
	const [showThankYouForms, setShowThankYou] = useState(false);
	const [surveys, setSurveys] = useState<Survey[]>([]);
	const [email, setEmail] = useState<string>();
	const [thisMarkers, setThisMarkers] = useState<google.maps.Marker[]>([]);
	const [circles, setCircles] = useState<google.maps.Circle[]>([]);
	const [pointDataArray, setPointDataArray] = useState<GeoReport | null>(null);
	const [distanceBetween, setDistanceBetween] = useState<number | null>(null);
	const [surveyNumber, setSurveyNumber] = useState(surveys.length + 1);
	const [selectedFile, setSelectedFile] = useState<File | null>(null);
	const [selectedImage, setSelectedImage] =useState<string>();

	const incrementCount = () => {
		setSurveyNumber(surveyNumber + 1);
	};

	const resetCount = () => {
		setSurveyNumber(1);
	};

	useEffect(() => {
		if (!map) return;
		if (thisMarkers.length == 0) {
			Object.entries(geoReportState.map).map(([, reports]) => {
				addMarkers(undefined, reports, thisMarkers, setThisMarkers, setPointDataArray);
				addCircles(undefined, setPointDataArray, reports, circles, setCircles);
			});
		}
		thisMarkers.forEach(marker => {
			marker.setMap(map);
		});
	}, [mapState]);

	useEffect(() => {
		if (!map) return;

		map.addListener('zoom_changed', () => {
			if (map.getZoom()! >= 11) {
				thisMarkers.forEach(marker => {
					marker.setMap(null);
				});
				circles.forEach(circle => {
					circle.setMap(map);
				});
			}
			if (map.getZoom()! < 11) {
				thisMarkers.forEach(marker => {
					marker.setMap(map);
				});
				circles.forEach(circle => {
					circle.setMap(null);
				});
			}
		});

	}, [map?.getZoom()]);

	thisMarkers.forEach(marker => {
		marker.addListener('click', () => {
			if (showSliderForms === true) {
				showSlider(false);
			}
		});
	});

	const handleOpenSlider = () => {
		showSlider(!showSliderForms);
		if (pointDataArray) {
			handleClosePointData();
		}
	};

	const handleOpenFileSubmit = () => {
		if (surveys.length === 0) {
			notificationHandler(2, 'Por favor introduza valores válidos', notificationDispatch);
		} else {
			setShowFileSubmit(!showFileSubmit);
		};
	};

	const handleOpenThankYou = () => {
		setShowThankYou(!showThankYouForms);
	};

	const handleClosePointData = () => {
		setPointDataArray(null);
		setDistanceBetween(null);
	};

	const handleSubmitNew = () => {
		setShowThankYou(!showThankYouForms);
		setShowFileSubmit(!showFileSubmit);
		setSurveys([]);
		resetCount();
		setSelectedFile(null);
		setSelectedImage('');
	};

	const handleExit = () => {
		setShowThankYou(!showThankYouForms);
		setShowFileSubmit(!showFileSubmit);
		showSlider(!showSliderForms);
		setSurveys([]);
		resetCount();
		setSelectedFile(null);
		setSelectedImage('');
	};

	const handleAddSurvey = (event: { preventDefault: () => void; }, lat: number, lng: number, nFreatico: boolean, inFreatico: number, nSPT: boolean, table: SurveyData[]) => {
		event.preventDefault();
		if (lat === 0 || lng === 0 || lat === undefined || lng === undefined || table.length === 0 || (nFreatico === true && (inFreatico === undefined || inFreatico === 0))) {
			notificationHandler(2, 'Por favor introduza valores válidos', notificationDispatch);
		} else {
            if(nSPT) {
                table.map(e => e.spt1 = 1000);
            }
			if (nFreatico === true) {
				const dummy = {
					lat: lat,
					lng: lng,
					nFreatico: nFreatico,
					inFreatico: inFreatico,
					table: table,
				};
				surveys.push(dummy);
			} else {
				const dummy = {
					lat: lat,
					lng: lng,
					nFreatico: nFreatico,
					inFreatico: 0,
					table: table,
				};
				surveys.push(dummy);
			};
			setSurveys([...surveys]);
			incrementCount();
			notificationHandler(1, 'Sondagem submetida com sucesso', notificationDispatch);
			surveyLengthHandler(surveys.length, surveyDispatch);
		}
	};

	const handleClearSurveys = (event: { preventDefault: () => void; }) => {
		event.preventDefault();
		setSurveys([]);
		resetCount();
	};

	const handleFileInput = (e: any, type: number) => {
		e.preventDefault();
		const file = e.target.files[0];
		if (type === 1) {
			if (file) {
				if (file.type === 'application/pdf') {
					setSelectedFile(file);
				} else {
					notificationHandler(
						2,
						'Por favor seleciona um ficheiro tipo PDF',
						notificationDispatch,
					);
				}
			}
		} else if (selectedImage) {
			setSelectedImage(file);
		} 
        // else {
		//	notificationHandler(
		//		2,
		//		'Por favor seleciona uma imagem do tipo PNG ou JPEG',
		//		notificationDispatch
		//	);
		//}
	};

	const handleUploadPDF = (e: any, filename: string) => {
		e.preventDefault();
		if (selectedFile) {
			const formPDFData = new FormData();
			formPDFData.append('filename', filename);
			formPDFData.append('file', selectedFile);
			fetch(process.env.REACT_APP_BACKEND + '/api/drive', {
				method: 'POST',
				body: formPDFData
			});
				//.then((response) => (console.log(response)))
				//.catch((error) => console.log(error));
		}
	};

	const handleUploadImage = (e: any, filename: string) => {
		e.preventDefault();
		if (selectedImage) {
			const formImgData = new FormData();
	//		formImgData.append('filename', filename);
			formImgData.append('image', selectedImage);
	//		fetch(process.env.REACT_APP_BACKEND + '/api/drive/image', {
	//			method: 'POST',
	//			body: formImgData,
	//		})
	//			.then((response) => console.log(response))
	//			.catch((error) => console.log(error));
		}
	};

	const handleSubmitForm = async (e: { preventDefault: () => void; }) => {
		e.preventDefault();

		if (!surveys[0]) {
			notificationHandler(
				2,
				'Não é possível submeter sem qualquer sondagem',
				notificationDispatch
			);
		}

		const lat = surveys[0].lat;
		const lng = surveys[surveys.length - 1].lng;

		const { adress, placeId } = await formSubmitGeoCoder(Number(lat), Number(lng), notificationDispatch);

        if(email) {
            if (selectedFile) {
                const fileName = selectedFile.name;
                const editedName = fileName.substring(0, fileName.length - 4);
                if (selectedImage) {
                //    const oldImgName = selectedImage.name;
                //    const imgExtension = oldImgName.substring(oldImgName.length - 4, oldImgName.length);
                //    const imgName = `logo_${editedName}${imgExtension}`;
                    formData = { adress, placeId, lat, lng, email, surveys, fileName, selectedImage };
                } else {
                    formData = { adress, placeId, lat, lng, email, surveys, fileName };
                }
                const requestOptions = {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(formData)
                };
                const response = await fetch(process.env.REACT_APP_BACKEND + '/api/report', requestOptions);
                if (response.ok) {
                    handleOpenThankYou();
                    setSurveys([]);
                    resetCount();
                    handleUploadPDF(e, selectedFile.name);
                    if (selectedImage) {
                    //    const oldImgName = selectedImage.name;
                    //    const imgExtension = oldImgName.substring(oldImgName.length - 4, oldImgName.length);
                    //    const imgName = `logo_${editedName}${imgExtension}`;
                       handleUploadImage(e, selectedImage);
                    };
                }
                if (!response.ok) {
                    notificationHandler(
                        2,
                        'Erro',
                        notificationDispatch
                    );
                }

            } else {
                notificationHandler(
                    2,
                    'Para validação do relatório iremos necessitar do mesmo em formato PDF',
                    notificationDispatch
                );
            }
        } else {
            notificationHandler(
				2,
				'Insira um e-mail para poder submeter os dados',
				notificationDispatch
			); 
        }
	};

	return (
		<>
			<div className='flex flex-col w-full h-full'>
				<Navbar setPointDataArray={setPointDataArray} setDistanceBetween={setDistanceBetween} />
				{showSliderForms ? (
					<>
						<div className='z-30'>
							<div className='bg-white sm:absolute sm:right-0 h-auto max-h-full sm:h-full sm:w-[40%] overflow-y-scroll'>
								{showThankYouForms ? (
									<>
										<ThankYou />
										<div className='justify-center mb-5 items-center flex space-x-2'>
											<button
												className='bg-blue-helica w-40 h-10 rounded-md text-xs text-white p-1'
												onClick={handleSubmitNew}
											>
												Submeter novo estudo
											</button>
											<button
												className='bg-blue-helica w-40 h-10 rounded-md text-xs text-white p-1'
												onClick={handleExit}
											>
												Sair
											</button>
										</div>
									</>
								) : (
									<>
										<button
											type='button'
											className='bg-white border ml-4 mt-4'
											onClick={handleOpenSlider}
										>
											<IconContext.Provider
												value={{
													color: '#000000',
													className: 'h-6 sm:h-9 w-6 sm:w-9',
												}}
											>
												<AiOutlineRight />
											</IconContext.Provider>
										</button>
										<form className='h-auto'>
											{showFileSubmit ? (
												<>
													<FileSubmit setEmail={setEmail} surveys={surveys} handleFileInput={handleFileInput} selectedFile={selectedFile} selectedImage={setSelectedImage} />
													<div className='justify-center mb-5 items-center flex space-x-2'>
														<button
															className='bg-blue-helica w-40 h-10 rounded-md text-xs text-white p-1'
															onClick={() => {
																handleOpenFileSubmit();
															}}
														>
															Passo Anterior
														</button>
														<button
															className='bg-blue-helica w-40 h-10 rounded-md text-xs text-white p-1'
															onClick={(event) => {
																handleSubmitForm(event);
															}}
														>
															Enviar
														</button>
													</div>
												</>
											) : (
												<>
													<Form handleOpenFileSubmit={handleOpenFileSubmit} handleAddSurvey={handleAddSurvey} handleClearSurveys={handleClearSurveys} surveyNumber={surveyNumber} />
												</>
											)}
										</form>
									</>
								)}
							</div>
						</div>
					</>
				) : (
					<>
						{pointDataArray ? (
							<>
								<div className='z-30'>
									<div className='bg-transparent right-[35%] absolute top-auto mt-3 h-auto max-h-full w-auto'>
                                        <button
											type='button'
											className='bg-white border'
											onClick={handleOpenSlider}
										>
											<IconContext.Provider
												value={{
													color: '#000000',
													className: 'h-6 sm:h-9 w-6 sm:w-9',
												}}
											>
												<AiOutlineLeft />
											</IconContext.Provider>
										</button>
									</div>
								</div>
							</>
						) : (
							<>
								<div className='z-30'>
									<div className='bg-transparent absolute right-4 top-auto mt-3 mr-12 h-auto max-h-full w-auto'>
                                        <button
                                            type='button'
                                            className='bg-white border mr-2 align-top'
                                            title='Recarregar pontos de sondagem'
                                        >
                                            <IconContext.Provider
                                            value={{
                                            color: '#000000',
                                            className: 'h-8 sm:h-10 w-8 sm:w-10',
                                        }}
                                    >
                                        <AiOutlineReload />
                                    </IconContext.Provider>
                                        </button>
                                        <button
											type='button'
											className='bg-white border'
											onClick={handleOpenSlider}
										>
											<IconContext.Provider
												value={{
													color: '#000000',
													className: 'h-12 sm:h-14 w-12 sm:w-14',
												}}
											>
												<AiOutlineLeft />
											</IconContext.Provider>
										</button>
									</div>
								</div>
							</>
						)}
					</>
				)}
				{pointDataArray ? (
					<>
						<div className='z-30'>
							<div className='bg-white absolute sm:right-0 h-auto max-h-full sm:h-full sm:w-1/3 overflow-y-scroll'>
								<PointData pointDataArray={pointDataArray} distance={distanceBetween} handleClosePointData={handleClosePointData} map={map} />
							</div>
						</div>
					</>
				) : (null)}
			</div>
		</>
	);
};

function addMarkers(
	map: google.maps.Map | undefined,
	reports: GeoReport[],
	thisMarkers: google.maps.Marker[],
	setThisMarkers: React.Dispatch<React.SetStateAction<google.maps.Marker[]>>,
	setPointDataArray: React.Dispatch<React.SetStateAction<GeoReport | null>>,
) {

	let isVisited = false;

	const markers = reports.map((report: GeoReport) => {

		const marker = new google.maps.Marker({
			position: { lat: report.lat, lng: report.lng },
            map: map,
			icon: Icon,
		});

		marker.addListener('click', () => {
			isVisited = !isVisited;
			if (isVisited === true) {
				setPointDataArray(report);
			}
		});

		thisMarkers.push(marker);
		setThisMarkers([...thisMarkers]);

		new MarkerClusterer({
			markers: thisMarkers,
			map,
			algorithm: new SuperClusterAlgorithm({ radius: 200 }),
		});

		return marker;
	});
}

const addCircles = (
	map: google.maps.Map | undefined,
	setPointDataArray: React.Dispatch<React.SetStateAction<GeoReport | null>>,
	reports: GeoReport[], circles: google.maps.Circle[],
	setCircles: React.Dispatch<SetStateAction<google.maps.Circle[]>>,
) => {

	let isVisited = false;
	const addresses: string[] = [];

	reports.map((report: GeoReport) => {

		report.surveys.map(survey => {
			survey.table.map(data => {
				addresses.push(data.soilType);
			});
		});

		let color = '#FFFFFFF';
		const soilType = findMode(addresses);
		if (soilType) {
			color = getSoilTypeColor(soilType);
		}
		const marker = new google.maps.Circle({
			center: { lat: report.lat, lng: report.lng },
			radius: 500,
			strokeColor: color,
			strokeOpacity: 0.8,
			strokeWeight: 2,
			fillColor: color,
			fillOpacity: 0.35,
			map,
		});

		marker.addListener('click', () => {
			isVisited = !isVisited;
			if (isVisited === true) {
				setPointDataArray(report);
			}
		});

		circles.push(marker);
		setCircles([...circles]);
		return marker;
	});
};

export default TestMap;

You can see here what I'm referring to! (I'm refreshing the website so it shows the problem)

Thanks in advance for any help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant