147 lines
4.9 KiB
TypeScript
147 lines
4.9 KiB
TypeScript
"use client"
|
|
|
|
import React, { useEffect, useRef } from 'react';
|
|
import mapboxgl from 'mapbox-gl';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { Badge } from "@/app/_components/ui/badge";
|
|
|
|
interface TimezoneLayerProps {
|
|
map: mapboxgl.Map | null;
|
|
}
|
|
|
|
// Component to display time in a specific timezone
|
|
function Jam({ timeZone }: { timeZone: string }) {
|
|
const [time, setTime] = React.useState<string>("");
|
|
|
|
useEffect(() => {
|
|
function updateTime() {
|
|
const now = new Date();
|
|
const options: Intl.DateTimeFormatOptions = {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false,
|
|
timeZone
|
|
};
|
|
setTime(now.toLocaleTimeString('id-ID', options));
|
|
}
|
|
|
|
updateTime();
|
|
const interval = setInterval(updateTime, 1000);
|
|
return () => clearInterval(interval);
|
|
}, [timeZone]);
|
|
|
|
return <>{time}</>;
|
|
}
|
|
|
|
export default function TimezoneLayer({ map }: TimezoneLayerProps) {
|
|
const hoverTimezone = useRef<any>(null);
|
|
const markersRef = useRef<mapboxgl.Marker[]>([]);
|
|
|
|
useEffect(() => {
|
|
if (!map) return;
|
|
|
|
// Function to add timezone data and markers
|
|
function addTimezoneLayers() {
|
|
// Add timezone data source
|
|
const url = "/geojson/timezones_wVVG8.geojson"; // Changed path to public folder
|
|
if (map && !map.getSource('timezone')) {
|
|
map.addSource('timezone', {
|
|
'type': 'geojson',
|
|
'generateId': true,
|
|
'data': url
|
|
});
|
|
|
|
// Add timezone boundaries
|
|
map.addLayer({
|
|
'id': 'timezone-line',
|
|
'type': 'line',
|
|
'source': 'timezone',
|
|
'layout': {},
|
|
'paint': {
|
|
'line-color': 'orange',
|
|
'line-width': 1,
|
|
'line-opacity': 0.5
|
|
}
|
|
});
|
|
|
|
// Create markers for Indonesian time zones
|
|
const createTimeMarker = (lngLat: [number, number], timeZone: string, label: string) => {
|
|
const markerElement = document.createElement('div');
|
|
const root = createRoot(markerElement);
|
|
root.render(
|
|
<div className='bordered p-1 text-time show-pop-up text-center'>
|
|
<p className="uppercase text-xl" style={{
|
|
lineHeight: "1rem"
|
|
}}>
|
|
<Jam timeZone={timeZone} />
|
|
</p>
|
|
<Badge variant="outline" className="text-xs mt-1">{label}</Badge>
|
|
</div>
|
|
);
|
|
|
|
const marker = new mapboxgl.Marker(markerElement)
|
|
.setLngLat(lngLat)
|
|
.addTo(map);
|
|
|
|
markersRef.current.push(marker);
|
|
return marker;
|
|
};
|
|
|
|
// WIB (GMT+7)
|
|
createTimeMarker([107.4999769225339, 3.4359354227361933], "Asia/Jakarta", "WIB / GMT+7");
|
|
|
|
// WITA (GMT+8)
|
|
createTimeMarker([119.1174733337183, 3.4359354227361933], "Asia/Makassar", "WITA / GMT+8");
|
|
|
|
// WIT (GMT+9)
|
|
createTimeMarker([131.58387377752751, 3.4359354227361933], "Asia/Jayapura", "WIT / GMT+9");
|
|
}
|
|
}
|
|
|
|
// Check if style is loaded, otherwise wait for it
|
|
if (map.isStyleLoaded()) {
|
|
addTimezoneLayers();
|
|
} else {
|
|
// Use both 'load' and 'style.load' events to ensure we catch the style loading
|
|
map.on('load', addTimezoneLayers);
|
|
map.on('style.load', addTimezoneLayers);
|
|
|
|
// Fallback: If style hasn't loaded within 2 seconds, try again
|
|
const timeoutId = setTimeout(() => {
|
|
if (map.isStyleLoaded()) {
|
|
addTimezoneLayers();
|
|
}
|
|
}, 2000);
|
|
|
|
// Clean up the timeout if component unmounts
|
|
return () => {
|
|
clearTimeout(timeoutId);
|
|
map.off('load', addTimezoneLayers);
|
|
map.off('style.load', addTimezoneLayers);
|
|
|
|
cleanupLayers();
|
|
};
|
|
}
|
|
|
|
function cleanupLayers() {
|
|
if (map && map.getLayer('timezone-line')) {
|
|
map.removeLayer('timezone-line');
|
|
}
|
|
if (map && map.getSource('timezone')) {
|
|
map.removeSource('timezone');
|
|
}
|
|
|
|
// Remove all markers
|
|
markersRef.current.forEach(marker => marker.remove());
|
|
markersRef.current = [];
|
|
}
|
|
|
|
// Clean up function
|
|
return () => {
|
|
cleanupLayers();
|
|
};
|
|
}, [map]);
|
|
|
|
return null;
|
|
}
|