diff --git a/sigap-website/app/(pages)/layout.tsx b/sigap-website/app/(pages)/layout.tsx
index d2cce73..effd8c5 100644
--- a/sigap-website/app/(pages)/layout.tsx
+++ b/sigap-website/app/(pages)/layout.tsx
@@ -1,7 +1,6 @@
import { Geist } from "next/font/google";
import { ThemeProvider } from "next-themes";
import "@/app/_styles/globals.css";
-import "@/app/_styles/ui.css";
import ReactQueryProvider from "@/app/_lib/react-query-provider";
import { Toaster } from "@/app/_components/ui/sonner";
diff --git a/sigap-website/app/_components/map/controls/example.tsx b/sigap-website/app/_components/map/controls/example.tsx
new file mode 100644
index 0000000..d349cd0
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/example.tsx
@@ -0,0 +1,2266 @@
+// 'use client'
+// import 'mapbox-gl/dist/mapbox-gl.css';
+// import mapboxgl from "mapbox-gl";
+// import './ui.css';
+// import React, { useRef, useEffect, useState } from 'react';
+// import io from 'socket.io-client'
+// import Worker from 'web-worker';
+// import TitikGempa from './components/mapbox_marker/titik_gempa';
+// import GempaBumiAlert from './components/GempaBumiAlert';
+// import * as turf from '@turf/turf'
+// import Card from './components/card/card';
+// import { createRoot } from 'react-dom/client';
+// import AnimatedPopup from 'mapbox-gl-animated-popup';
+// import ItemKotaTerdampak from './components/ItemKotaTerdampak';
+// import { KotaTerdampak, InfoGempa, InfoTsunami } from "../libs/interface";
+// import Jam from './components/Jam';
+// const { DateTime } = require("luxon");
+// import { IoLocationSharp } from "react-icons/io5";
+// import { XMLParser, XMLBuilder, XMLValidator } from "fast-xml-parser";
+// import TitikTsunami from './components/mapbox_marker/titik_tsunami';
+
+// // import { HexGrid, Layout, Hexagon, Text, Pattern, Path, Hex, GridGenerator, HexUtils } from 'react-hexgrid';
+// // import { css } from "@emotion/react"
+
+// // const initialConfig: any = {
+// // width: 1000,
+// // height: 800,
+// // layout: { width: 8, height: 8, flat: false, spacing: 1.02 },
+// // origin: { x: 0, y: 0 },
+// // map: "parallelogram",
+// // mapProps: [10],
+// // }
+// // const generator = GridGenerator.getGenerator(initialConfig.map)
+
+// // const initialHexagons: Hex[] = generator(initialConfig.mapProps)
+
+
+// mapboxgl.accessToken = 'pk.eyJ1IjoiYmFndXNpbmRyYXlhbmEiLCJhIjoiY2p0dHMxN2ZhMWV5bjRlbnNwdGY4MHFuNSJ9.0j5UAU7dprNjZrouWnoJyg';
+
+
+
+// let socket;
+// export default function Home() {
+// // const [hexagons, setHexagons] = React.useState(initialHexagons)
+// // const [config, setConfig] = React.useState(initialConfig)
+
+// // const layout = config.layout
+// // const size = { x: layout.width, y: layout.height }
+
+// const dangerSound = "/sounds/siren-alarm-96503.mp3"
+// const smallEarthQuakeSound = "/sounds/wrong-answer-129254.mp3"
+// const tsunamiAlertSound = "sounds/security-alarm-80493.mp3"
+// const mapContainer = useRef(null); // Update the type of mapContainer ref
+// const map = useRef(null); // Update the type of the map ref
+// const [lng, setLng] = useState(123.90146694265115);
+// const [lat, setLat] = useState(-1.370489908625089);
+// const [zoom, setZoom] = useState(5);
+
+// const geoJsonData = useRef(null);
+// const geoJsonCoastline = useRef(null);
+// const geoJsonTitikGempa = useRef(null);
+// const worker = useRef(null);
+// const adaGempa = useRef(false);
+// const tgs = useRef([]);
+// const titikGempaBaru = useRef([]);
+
+// const tts = useRef([]);
+
+// const kts = useRef([]);
+// const markerDaerahs = useRef([]);
+// const daerahTsunami = useRef([]);
+
+// const lastGempaId = useRef('');
+// const lastGempaKecilId = useRef('');
+
+// const [detailInfoGempa, setDetailInfoGempa] = useState(null);
+// const [loadingScreen, setLoadingScreen] = useState(true);
+
+// const [gempaDirasakan, setGempaDirasakan] = useState(null);
+// const [gempaTerakhir, setGempaTerakhir] = useState(null);
+// const [events, setEvents] = useState([]);
+// const [alertGempaBumi, setAlertGempaBumi] = useState(null);
+
+// const [alertGempaBumis, setAlertGempaBumis] = useState([]);
+
+// const [alertTsunami, setAlertTsunami] = useState(null);
+
+
+// const [infoTsunami, setInfoTsunami] = useState(null);
+// const blinkInterval = useRef(null);
+
+
+// const warningHandler = async (data: any) => {
+// console.log("WARNING!!!");
+// const time = new Date().toLocaleTimeString();
+// const id = data.id ?? `tg-${time}`;
+
+
+// if (!map.current) return;
+// // map.current.flyTo({
+// // center: [data.lng, data.lat],
+// // zoom: 7,
+// // essential: true
+// // });
+
+// const nig: InfoGempa = {
+// id: id,
+// lng: parseFloat(data.lng),
+// lat: parseFloat(data.lat),
+// mag: parseFloat(data.mag || 9.0),
+// depth: data.depth || "10 Km",
+// message: data.message,
+// place: data.place,
+// time: data.time || new Date().toLocaleString(),
+// listKotaTerdampak: []
+// };
+
+// const tg = new TitikGempa(id, nig, {
+// pWaveSpeed: 6000,
+// sWaveSpeed: 3000,
+// map: map.current!,
+// showMarker: true,
+// description: data.message,
+// showPopup: true,
+// showPopUpInSecond: 6,
+// zoomToPosition: true
+// });
+// tgs.current.push(tg);
+// titikGempaBaru.current.push(tg);
+
+
+// setAlertGempaBumis([...alertGempaBumis, nig]);
+
+
+// // tgs.current.push(tg);
+// // tgs.current.sort(function (a: any, b: any) {
+// // return new Date(b.time).getTime() - new Date(a.time).getTime();
+// // });
+
+// const audioDangerElement = document.getElementById('danger');
+// setTimeout(() => {
+
+// if (audioDangerElement) {
+// (audioDangerElement as HTMLAudioElement).play();
+// }
+// setTimeout(() => {
+// var voice = new Audio("/voice/gempabumi.wav");
+// voice.play();
+// }, 2000);
+// }, 2000);
+
+
+// await new Promise(r => setTimeout(r, 6000));
+
+// setEvents(tgs.current);
+// if (worker.current != null) {
+// adaGempa.current = true;
+// console.log("Send Wave");
+// sendWave();
+// }
+// if (audioDangerElement) {
+// //set volume down
+// (audioDangerElement as HTMLAudioElement).volume = 0.5;
+// }
+
+// }
+
+// function blinkCoastline() {
+// if (blinkInterval.current) {
+// clearInterval(blinkInterval.current);
+// }
+// blinkInterval.current = setInterval(() => {
+// const visibility = map.current!.getLayoutProperty(
+// 'outline-coastline',
+// 'visibility'
+// );
+// map.current!.setLayoutProperty(
+// 'outline-coastline',
+// 'visibility',
+// visibility == 'visible' ? 'none' : 'visible'
+// );
+// }, 1000);
+
+// }
+
+// const warningTsunamiHandler = async (data: any) => {
+// // setInfoTsunami(data);
+// if (blinkInterval.current) {
+// clearInterval(blinkInterval.current);
+// }
+// const results: any = [];
+// daerahTsunami.current = [];
+
+// const time = new Date().toLocaleTimeString();
+// const id = data.id ?? `tg-${time}`;
+
+// const coordinates = data.point.coordinates.split(",");
+// const nit: InfoTsunami = {
+// id: id,
+// lng: parseFloat(coordinates[0]),
+// lat: parseFloat(coordinates[1]),
+// message: data.description + "\n" + data.instruction,
+// level: data.subject,
+// time: data.time || new Date().toLocaleString(),
+// listKotaTerdampak: []
+// };
+
+// let level = "WASPADA";
+
+// for (let x = 0; x < data.wzarea.length; x++) {
+// const wz = data.wzarea[x];
+// const cek = geoJsonCoastline.current.features.find((f) =>
+// wz.district.replaceAll("-", " ")
+// .replaceAll("PULAU ", "")
+// .replaceAll("KEPULAUAN ", "")
+// .replaceAll(" BAGIAN UTARA", "")
+// .replaceAll(" BAGIAN BARAT", "")
+// .replaceAll(" BAGIAN SELATAN", "")
+// .replaceAll(" BAGIAN TIMUR", "")
+// ===
+// f.properties.alt_name.replaceAll("KABUPATEN ", "")
+// .replaceAll("PULAU ", "")
+// .replaceAll("KEPULAUAN ", ""));
+// if (cek) {
+
+// let color = "yellow";
+// if (wz.level == "SIAGA") {
+// color = "orange";
+// } else if (wz.level == "AWAS") {
+// color = "red";
+// }
+// if (level == "WASPADA" && wz.level == "SIAGA") {
+// level = wz.level;
+// }
+
+// if (level == "SIAGA" && wz.level == "AWAS") {
+// level = wz.level;
+// }
+
+
+// cek.properties.color = color;
+// results.push(cek);
+
+// const dist = turf.distance(turf.point([nit.lng, nit.lat]), turf.point([cek.properties.longitude, cek.properties.latitude]));
+// const timeDist = Math.floor(dist / 3) * 1000;
+// nit.listKotaTerdampak!.push({
+// lng: cek.properties.longitude,
+// lat: cek.properties.latitude,
+// distance: dist,
+// name: cek.properties.alt_name,
+// hit: false,
+// timeArrival: new Date(new Date().getTime() + timeDist)
+// });
+// } else {
+// // console.log(info.wzarea);
+// console.log(wz);
+// }
+
+// nit.listKotaTerdampak!.sort((a, b) => a.distance - b.distance);
+
+// }
+
+// for (let x = 0; x < results.length; x++) {
+// const element = results[x];
+// const p: number[] = turf.centroid(element).geometry.coordinates;
+// if (markerDaerahs.current.findIndex((el) => el[0] == p[0] && el[1] == p[1]) == -1) {
+// markerDaerahs.current.push([p[0], p[1]]);
+// const markerParent = document.createElement('div');
+// const markerEl = document.createElement('div');
+// markerEl.innerHTML = '' + element.properties.alt_name + '
';
+// markerEl.classList.add('marker-daerah');
+// markerEl.classList.add('show-pop-up');
+// markerParent.appendChild(markerEl);
+// new mapboxgl.Marker(markerParent)
+// .setLngLat([p[0], p[1]])
+// .addTo(map.current!)
+
+// }
+
+// }
+
+// const tt = new TitikTsunami(id, nit, {
+// pWaveSpeed: 6000,
+// sWaveSpeed: 3000,
+// map: map.current!,
+// showMarker: true,
+// description: data.description + "\n" + data.instruction,
+// showPopup: true,
+// showPopUpInSecond: 6,
+// zoomToPosition: true,
+// closePopUpInSecond: 13
+// });
+// tts.current.push(tt);
+
+// setAlertTsunami(tt);
+
+
+// daerahTsunami.current = results;
+// if (results.length > 0) {
+// if (map.current!.getSource('coastline')) {
+// (map.current!.getSource('coastline') as mapboxgl.GeoJSONSource).setData({ "type": "FeatureCollection", "features": results });
+// } else {
+// map.current!.addSource('coastline', {
+// 'type': 'geojson',
+// 'data': { "type": "FeatureCollection", "features": results }
+// });
+// }
+// map.current!.setLayoutProperty(
+// 'outline-coastline',
+// 'visibility',
+// 'visible'
+// );
+
+// } else {
+// testDemoTsunami();
+// return;
+// }
+
+
+
+// if (!map.current) return;
+// // map.current.flyTo({
+// // center: [coordinates[0], coordinates[1]],
+// // zoom: 7,
+// // essential: true
+// // });
+
+
+// blinkCoastline();
+// map.current!.moveLayer('outline-coastline');
+
+// // tgs.current.push(nt);
+// // setEvents(tgs.current);
+
+// console.log("WARNING TSUNAMI!!!");
+
+// var notif = new Audio(tsunamiAlertSound);
+// notif.loop = true;
+// notif.play();
+// setTimeout(() => {
+// var voice = new Audio("/voice/terdeteksi.wav");
+// voice.play();
+
+// setTimeout(() => {
+// var voice = new Audio("/voice/" + level.toLowerCase() + ".wav");
+// voice.play();
+// setTimeout(() => {
+// var voice = new Audio("/voice/potensi.wav");
+// voice.play();
+
+// if (level == "AWAS") {
+// setTimeout(() => {
+// var voice = new Audio("/voice/evakuasi.wav");
+// voice.play();
+// setTimeout(() => {
+// notif.pause();
+// }, 2000);
+// }, 6000);
+// } else {
+// setTimeout(() => {
+// var voice = new Audio("/voice/informasi.wav");
+// voice.play();
+// setTimeout(() => {
+// notif.pause();
+// }, 2000);
+// }, 6000);
+// }
+
+// }, 5000);
+// }, 5000);
+// }, 2000);
+
+
+// setTimeout(() => {
+// const tsunamiWarning: HTMLDivElement = document.querySelector("#tsunami-warning") as HTMLDivElement;
+// //find div inside bg-tsunami
+// if (tsunamiWarning) {
+// const divs = tsunamiWarning.querySelectorAll(".show-pop-up");
+// //loop and add class close-pop-up
+// divs.forEach((v) => {
+// v.classList.add("close-pop-up");
+// });
+// }
+// }, 9000);
+// setTimeout(() => {
+
+
+// const bgTsunami: HTMLDivElement = document.querySelector("#bg-tsunami .hex-bg") as HTMLDivElement;
+// //find div inside bg-tsunami
+// if (bgTsunami) {
+// const divs = bgTsunami.querySelectorAll("div");
+// //loop and add class close-pop-up
+// divs.forEach((v) => {
+// v.classList.add("close-pop-up");
+// });
+// }
+// setTimeout(() => {
+// setAlertTsunami(null);
+// }, 1000);
+// setInfoTsunami(tt);
+// }, 10000);
+// }
+
+// const socketInitializer = () => {
+// if (socket != null) return;
+// fetch('/api/socket')
+// .then(() => {
+
+// console.log('Socket is initializing');
+
+// socket = io();
+
+// socket.on('connect', () => {
+// console.log('connected');
+// });
+// socket.on('warning', (v: any) => {
+
+// warningHandler(v);
+// });
+// socket.on('message', (v: any) => {
+
+// console.log(v);
+// });
+
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+// };
+
+// const initWorker = () => {
+// worker.current = new Worker(
+// new URL('./worker.mjs', import.meta.url),
+// { type: 'module' }
+// );
+
+// worker.current.postMessage({ type: 'geoJsonData', data: geoJsonData.current, coastline: geoJsonCoastline.current });
+
+// worker.current.addEventListener('message', (event: any) => {
+// const data = event.data;
+// if (data.type == "checkMultiHighlightArea" && data.id == "wave") {
+// recieveWave(data);
+// }
+// });
+// }
+
+
+
+
+// useEffect(() => {
+// if (map.current) return () => { };
+// map.current = new mapboxgl.Map({
+// container: mapContainer.current!,
+// style: 'mapbox://styles/mapbox/dark-v11',
+// center: [lng, lat],
+// zoom: zoom,
+// maxZoom: 22,
+// });
+
+// map.current.on('load', () => {
+// // loadGeoJsonData();
+// loadGeoJsonCoastline();
+// });
+
+
+// });
+
+// useEffect(() => {
+
+// socketInitializer();
+
+// if (socket) return () => {
+// socket!.disconnect();
+// };
+
+// });
+
+
+
+// const sendWave = () => {
+// let t: any = [];
+// for (let i = 0; i < titikGempaBaru.current.length; i++) {
+// const v = titikGempaBaru.current[i];
+// if (!v.finish) {
+// t.push({
+// id: v.id,
+// center: v.center,
+// mag: v.mag,
+// depth: v.depth,
+// pWaveRadius: v.pWaveRadius,
+// sWaveRadius: v.sWaveRadius,
+// areaTerdampak: [],
+// message: v.description
+// })
+// }
+
+// }
+// if (t.length > 0) {
+// worker.current!.postMessage({ type: 'checkMultiHighlightArea', titikGempa: t, id: "wave" });
+// } else {
+// console.log("Not Send Wave");
+// }
+// }
+
+
+// const isEqual = (a, b) => a.id === b.id && a.name === b.name;
+
+
+// const recieveWave = async (data: any) => {
+// let alerts: InfoGempa[] = [];
+// for (let x = 0; x < data.titikGempa.length; x++) {
+// const tg = data.titikGempa[x];
+
+// const nig: InfoGempa = {
+// id: tg.id,
+// lng: parseFloat(tg.center[1]),
+// lat: parseFloat(tg.center[0]),
+// mag: tg.mag,
+// depth: tg.depth,
+// message: tg.message,
+// place: tg.place,
+// time: new Date().toLocaleString(),
+// listKotaTerdampak: []
+// };
+
+// for (let il = 0; il < tg.areaTerdampak.length; il++) {
+// const at = tg.areaTerdampak[il];
+// const dist = turf.distance(turf.point([tg.center[0], tg.center[1]]), turf.point([at.center[0], at.center[1]])) - (tg.sWaveRadius / 1000);
+// const time = Math.floor(dist / 3) * 1000;
+// nig.listKotaTerdampak!.push({
+// lng: at.center[1],
+// lat: at.center[0],
+// distance: dist,
+// name: at.alt_name,
+// hit: at.hit,
+// timeArrival: new Date(new Date().getTime() + time)
+// });
+
+// }
+
+// //sort nig.listKotaTerdampak by distance
+// nig.listKotaTerdampak!.sort((a, b) => a.distance - b.distance);
+
+// alerts.push(nig);
+// }
+
+// //get last alert
+// if (alerts.length > 0) {
+// const fig = alerts.slice(-1).pop()!;
+// setAlertGempaBumi(new TitikGempa(fig.id, fig));
+// } else {
+// setAlertGempaBumi(null);
+// }
+
+// const areas = data.area;
+
+// // Hapus data array objek yang sama
+// // const uniqueData = areas.filter((obj, index, self) =>
+// // index === self.findIndex((t) => isEqual(t.properties.mhid, obj.properties.mhid))
+// // );
+
+// const uniqueData = areas;
+
+// for (let x = 0; x < uniqueData.length; x++) {
+// const element = uniqueData[x];
+// const p: number[] = turf.centroid(element).geometry.coordinates;
+// if (markerDaerahs.current.findIndex((el) => el[0] == p[0] && el[1] == p[1]) == -1) {
+// markerDaerahs.current.push([p[0], p[1]]);
+// const markerParent = document.createElement('div');
+// const markerEl = document.createElement('div');
+// markerEl.innerHTML = '' + element.properties.alt_name + '
';
+// markerEl.classList.add('marker-daerah');
+// markerEl.classList.add('show-pop-up');
+// markerParent.appendChild(markerEl);
+// new mapboxgl.Marker(markerParent)
+// .setLngLat([p[0], p[1]])
+// .addTo(map.current!)
+
+// } else {
+
+// const index = kts.current.findIndex((el) => el.lng == p[0] && el.lat == p[1]);
+// if (index != -1) {
+
+// // kts.current[index].distance += 16;
+// // kts.current[index].hit = element.properties.hit;
+// // setKotaTerdampak([...kotaTerdampak, ...kts.current]);
+// // countdownTime();
+// }
+// }
+
+
+// }
+
+// if (map.current!.getSource('hightlight-wave')) {
+// (map.current!.getSource('hightlight-wave') as mapboxgl.GeoJSONSource).setData({ "type": "FeatureCollection", "features": uniqueData });
+// } else {
+// map.current!.addSource('hightlight-wave', {
+// 'type': 'geojson',
+// 'data': { "type": "FeatureCollection", "features": uniqueData }
+// });
+// }
+
+// if (!map.current!.getLayer('hightlight-wave-layer')) {
+// map.current!.addLayer({
+// 'id': 'hightlight-wave-layer',
+// 'type': 'fill',
+// 'source': 'hightlight-wave',
+// 'layout': {},
+// 'paint': {
+// 'fill-color': ['get', 'color'],
+// 'fill-opacity': 0.8
+// }
+// });
+
+// map.current!.moveLayer('outline');
+// map.current!.moveLayer('outline-coastline');
+// for (let tg of tgs.current) {
+// if (map.current!.getLayer(tg.id)) {
+// map.current!.moveLayer(tg.id);
+// }
+// }
+// }
+
+// // if (map.current!.getSource('coastline')) {
+// // (map.current!.getSource('coastline') as mapboxgl.GeoJSONSource).setData({ "type": "FeatureCollection", "features": data.line });
+// // } else {
+// // map.current!.addSource('coastline', {
+// // 'type': 'geojson',
+// // 'data': { "type": "FeatureCollection", "features": data.line }
+// // });
+// // }
+
+// sendWave();
+// }
+
+// const hoverWilayah = useRef(null);
+
+// function loadGeoJsonCoastline() {
+// fetch('/geojson/garis_pantai.geojson')
+// .then(response => response.json())
+// .then(data => {
+// geoJsonCoastline.current = data;
+// if (!map.current!.getSource('coastline')) {
+// map.current!.addSource('coastline', {
+// type: 'geojson',
+// generateId: true,
+// data: data
+// });
+// map.current!.addLayer({
+// 'id': 'outline-coastline',
+// 'type': 'line',
+// 'source': 'coastline',
+// 'layout': {
+// 'visibility': 'none',
+// },
+// 'paint': {
+// 'line-color': ['get', 'color'],
+// 'line-width': 5,
+// 'line-opacity': 1
+// }
+// });
+
+// }
+// loadGeoJsonData();
+// }).catch((error) => {
+// alert("Failed load geojson data : " + error);
+// console.error('Error fetching data:', error);
+// });
+// };
+
+// function loadGeoJsonData() {
+// fetch('/geojson/all_kabkota_ind_reduce.geojson')
+// .then(response => response.json())
+// .then(data => {
+// geoJsonData.current = data;
+// if (!map.current!.getSource('wilayah')) {
+// map.current!.addSource('wilayah', {
+// type: 'geojson',
+// generateId: true,
+// data: data
+// });
+// map.current!.addLayer({
+// 'id': 'outline',
+// 'type': 'line',
+// 'source': 'wilayah',
+// 'layout': {},
+// 'paint': {
+// 'line-color': '#807a72',
+// 'line-width': 1,
+// 'line-opacity': 0.7
+// }
+// });
+
+// map.current!.addLayer({
+// 'id': 'wilayah-fill',
+// 'type': 'fill',
+// 'source': 'wilayah',
+// 'layout': {
+
+// },
+// 'paint': {
+// 'fill-color': 'red',
+// 'fill-opacity': [
+// 'case',
+// ['boolean', ['feature-state', 'hover'], false],
+// 0.1,
+// 0
+// ],
+
+// }
+// });
+
+// // map.current!.on('mousemove', 'wilayah-fill', (e: any) => {
+// // if (e.features.length > 0) {
+// // if (hoverWilayah.current !== null) {
+// // map.current!.setFeatureState(
+// // { source: 'wilayah', id: hoverWilayah.current },
+// // { hover: false }
+// // );
+// // }
+// // hoverWilayah.current = e.features[0].id;
+// // map.current!.setFeatureState(
+// // { source: 'wilayah', id: hoverWilayah.current },
+// // { hover: true }
+// // );
+// // }
+// // });
+
+// // map.current!.on('mouseleave', 'wilayah-fill', () => {
+// // if (hoverWilayah.current !== null) {
+// // map.current!.setFeatureState(
+// // { source: 'wilayah', id: hoverWilayah.current },
+// // { hover: false }
+// // );
+// // }
+// // hoverWilayah.current = null;
+// // });
+// }
+// // getTitikStationJson();
+// getTitikGempaJson();
+// getTimezoneGeojson();
+// getFaultLineGeojson();
+// initWorker();
+// }).catch((error) => {
+// alert("Failed load geojson data : " + error);
+// console.error('Error fetching data:', error);
+// });
+// };
+
+// function getTitikStationJson() {
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/sensor_seismic.json";
+// if (map.current) {
+// map.current.loadImage(
+// '/images/triangle-filled-svgrepo-com.png',
+// (error, image: any) => {
+// if (error) throw error;
+
+// // Add the image to the map style.
+// map.current!.addImage('station-icon', image);
+
+// // Add a data source containing one point feature.
+// map.current!.addSource('station', {
+// 'type': 'geojson',
+// 'data': url
+// });
+
+// // Add a layer to use the image to represent the data.
+// map.current!.addLayer({
+// 'id': 'stations',
+// 'type': 'symbol',
+// 'source': 'station', // reference the data source
+// 'layout': {
+// 'icon-image': 'station-icon', // reference the image
+// 'icon-size': 0.05
+// }
+// });
+
+// map.current!.on('click', 'stations', (e: any) => {
+// // Copy coordinates array.
+// const coordinates = e.features[0].geometry.coordinates.slice();
+// const d = e.features[0].properties;
+// const placeholder = document.createElement('div');
+// const root = createRoot(placeholder)
+// root.render(SENSOR SEISMIK
+// } className='min-h-48 min-w-48 whitespace-pre-wrap' >
+//
+//
+//
+// ID |
+// {d.id} |
+//
+//
+// Stakeholder |
+// {d.stakeholder} |
+//
+//
+// UPTBMKG |
+// {d.uptbmkg} |
+//
+//
+// Lokasi (Lat,Lng) |
+// {coordinates[0]} , {coordinates[1]} |
+//
+//
+//
+//
+// );
+
+// new AnimatedPopup({
+// openingAnimation: {
+// duration: 100,
+// easing: 'easeOutSine',
+// transform: 'scale'
+// },
+// closingAnimation: {
+// duration: 100,
+// easing: 'easeInOutSine',
+// transform: 'scale'
+// }
+// }).setDOMContent(placeholder).setLngLat(coordinates).addTo(map.current!);
+// });
+
+// map.current!.on('mouseenter', 'stations', () => {
+// map.current!.getCanvas().style.cursor = 'pointer';
+// });
+
+// // Change it back to a pointer when it leaves.
+// map.current!.on('mouseleave', 'stations', () => {
+// map.current!.getCanvas().style.cursor = '';
+// });
+// }
+// );
+
+// }
+// }
+
+// function getTitikGempaJson() {
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/gempaQL.json?t=" + new Date().getTime();
+// fetch(url)
+// .then(response => response.json())
+// .then((data) => {
+// geoJsonTitikGempa.current = data;
+// setTimeout(() => {
+// document.getElementById("loading-screen")!.style.display = "none";
+// setLoadingScreen(false);
+// }, 1000);
+// let ntg: TitikGempa[] = [];
+// for (let index = 0; index < data.features.length; index++) {
+// const feature = data.features[index];
+// const dt = DateTime.fromSQL(feature.properties.time, { zone: 'UTC' }).setZone("Asia/Jakarta");
+// const readAbleTime = dt.toISODate() + " " + dt.toLocaleString(DateTime.TIME_24_WITH_SECONDS)
+// ntg.push(new TitikGempa(feature.properties.id, {
+// id: feature.properties.id,
+// lng: feature.geometry.coordinates[0],
+// lat: feature.geometry.coordinates[1],
+// mag: feature.properties.mag,
+// depth: feature.properties.depth,
+// place: feature.properties.place,
+// time: readAbleTime
+// }));
+// }
+// tgs.current = ntg;
+// setEvents(tgs.current);
+// console.log('load titik gempa 1');
+// //check earthquakes layer
+// if (map.current!.getLayer('earthquakes-layer')) {
+// //update source
+// (map.current!.getSource('earthquakes') as mapboxgl.GeoJSONSource).setData(data);
+// } else {
+// //add source
+// map.current!.addSource('earthquakes', {
+// type: 'geojson',
+// data: data
+// });
+
+// map.current!.addLayer({
+// 'id': 'earthquakes-layer',
+// 'type': 'circle',
+// 'source': 'earthquakes',
+// 'paint': {
+// 'circle-radius': ["to-number", ['get', 'mag']],
+// 'circle-stroke-width': 2,
+
+// 'circle-color': [
+// "case",
+// //depth <= 50 red, depth <= 100 orange, depth <= 250 yellow, depth <= 600 green, depth > 600 blue
+// ['<=', ["to-number", ['get', 'depth']], 50],
+// "red",
+// ['<=', ["to-number", ['get', 'depth']], 100],
+// "orange",
+// ['<=', ["to-number", ['get', 'depth']], 250],
+// "yellow",
+// ['<=', ["to-number", ['get', 'depth']], 600],
+// "green",
+// "blue",
+// ],
+// 'circle-stroke-color': 'white'
+// }
+// });
+// }
+
+// map.current!.on('click', 'earthquakes-layer', (e: any) => {
+// // Copy coordinates array.
+// const coordinates = e.features[0].geometry.coordinates.slice();
+// const d = e.features[0].properties;
+// const placeholder = document.createElement('div');
+// const root = createRoot(placeholder)
+// root.render(
+//
+//
+//
+// } className='min-h-48 min-w-48 whitespace-pre-wrap' >
+//
+//
+//
+// Magnitudo |
+// {d.mag} |
+//
+//
+// Kedalaman |
+// {d.depth} |
+//
+//
+// Waktu |
+// {new Date(d.time!).toLocaleString()} |
+//
+//
+// Lokasi (Lat,Lng) |
+// {coordinates[0]} , {coordinates[1]} |
+//
+//
+//
+//
+// );
+
+// new AnimatedPopup({
+// openingAnimation: {
+// duration: 100,
+// easing: 'easeOutSine',
+// transform: 'scale'
+// },
+// closingAnimation: {
+// duration: 100,
+// easing: 'easeInOutSine',
+// transform: 'scale'
+// }
+// }).setDOMContent(placeholder).setLngLat(coordinates).addTo(map.current!);
+// });
+
+// map.current!.on('mouseenter', 'earthquakes-layer', () => {
+// map.current!.getCanvas().style.cursor = 'pointer';
+// });
+
+// // Change it back to a pointer when it leaves.
+// map.current!.on('mouseleave', 'earthquakes-layer', () => {
+// map.current!.getCanvas().style.cursor = '';
+// });
+
+// console.log('load titik gempa 2');
+
+// getGempa();
+// getGempaKecil();
+
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+
+// }
+
+// const hoverTimezone = useRef(null);
+// function getTimezoneGeojson() {
+// const url = "/geojson/timezones_wVVG8.geojson";
+// map.current!.addSource('timezone', {
+// 'type': 'geojson',
+// 'generateId': true,
+// 'data': url
+// });
+
+// // Add a layer to use the image to represent the data.
+// // map.current!.addLayer({
+// // 'id': 'timezone-fill',
+// // 'type': 'fill',
+// // 'source': 'timezone', // reference the data source
+// // 'layout': {
+
+// // },
+// // 'paint': {
+// // // 'line-color': 'blue',
+// // // 'line-width': 1
+// // 'fill-color': 'red',
+// // 'fill-opacity': [
+// // 'case',
+// // ['boolean', ['feature-state', 'hover'], false],
+// // 0.1,
+// // 0
+// // ],
+
+// // }
+// // });
+
+// map.current!.addLayer({
+// 'id': 'timezone-line',
+// 'type': 'line',
+// 'source': 'timezone', // reference the data source
+// 'layout': {
+
+// },
+// 'paint': {
+// 'line-color': 'orange',
+// 'line-width': 1,
+// 'line-opacity': 0.5
+// }
+// });
+
+// const markerParent1 = document.createElement('div');
+// const gmt7Marker = createRoot(markerParent1)
+// gmt7Marker.render(
+//
+//
+//
+//
+//
WIB / GMT+7
+//
+// );
+
+// new mapboxgl.Marker(markerParent1)
+// .setLngLat([107.4999769225339, 3.4359354227361933])
+// .addTo(map.current!);
+
+
+// const markerParent2 = document.createElement('div');
+// const gmt8Marker = createRoot(markerParent2)
+// gmt8Marker.render(
+//
+//
+//
+//
+//
WITA / GMT+8
+//
+// );
+// new mapboxgl.Marker(markerParent2)
+// .setLngLat([119.1174733337183, 3.4359354227361933])
+// .addTo(map.current!);
+
+// const markerParent3 = document.createElement('div');
+// const gmt9Marker = createRoot(markerParent3)
+// gmt9Marker.render(
+//
+//
+//
+//
+//
WIT / GMT+9
+//
+// );
+// new mapboxgl.Marker(markerParent3)
+// .setLngLat([131.58387377752751, 3.4359354227361933])
+// .addTo(map.current!)
+
+// // map.current!.on('click', 'timezone-fill', (e: any) => {
+// // console.log(e);
+// // });
+
+// // map.current!.on('mousemove', 'timezone-fill', (e: any) => {
+// // if (e.features.length > 0) {
+// // if (hoverTimezone.current !== null) {
+// // map.current!.setFeatureState(
+// // { source: 'timezone', id: hoverTimezone.current },
+// // { hover: false }
+// // );
+// // }
+// // hoverTimezone.current = e.features[0].id;
+// // map.current!.setFeatureState(
+// // { source: 'timezone', id: hoverTimezone.current },
+// // { hover: true }
+// // );
+// // }
+// // });
+
+// // map.current!.on('mouseleave', 'timezone-fill', () => {
+// // if (hoverTimezone.current !== null) {
+// // map.current!.setFeatureState(
+// // { source: 'timezone', id: hoverTimezone.current },
+// // { hover: false }
+// // );
+// // }
+// // hoverTimezone.current = null;
+// // });
+// }
+
+// function getFaultLineGeojson() {
+// const url = "/geojson/indo_faults_lines.geojson";
+// map.current!.addSource('indo_faults_lines', {
+// 'type': 'geojson',
+// 'generateId': true,
+// 'data': url
+// });
+
+// // Add a layer to use the image to represent the data.
+// map.current!.addLayer({
+// 'id': 'indo_faults_line_layer',
+// 'type': 'line',
+// 'source': 'indo_faults_lines', // reference the data source
+// 'layout': {
+
+// },
+// 'paint': {
+// 'line-color': 'red',
+// 'line-width': 1,
+// 'line-opacity': 0.5
+// // 'fill-color': 'red',
+// // 'fill-opacity': [
+// // 'case',
+// // ['boolean', ['feature-state', 'hover'], false],
+// // 0.1,
+// // 0
+// // ],
+
+// }
+// });
+
+
+
+// }
+
+// function getGempa() {
+// if (lastGempaId.current) {
+// return
+// }
+// console.log("getGempa");
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/datagempa.json?t=" + new Date().getTime();
+// fetch(url)
+// .then(response => response.json())
+// .then((data) => {
+// const coordinates = data.info.point.coordinates.split(",");
+// lastGempaId.current = data.identifier;
+// const sentTime = DateTime.fromISO(data.sent.replace("WIB", ""), { zone: "Asia/Jakarta" });
+// const currentTime = DateTime.now().setZone("Asia/Jakarta");
+// const readAbleTime = sentTime.toISODate() + " " + sentTime.toLocaleString(DateTime.TIME_24_WITH_SECONDS)
+
+// const nig: InfoGempa = {
+// id: data.identifier,
+// lng: parseFloat(coordinates[0]),
+// lat: parseFloat(coordinates[1]),
+// mag: data.info.magnitude || 9.0,
+// depth: data.info.depth || "10 Km",
+// message: data.info.description,
+// time: readAbleTime
+// };
+
+// const cek = tgs.current.find((v) => v.id == data.identifier);
+// if ((currentTime.toMillis() - sentTime.toMillis()) < 600000) {
+// warningHandler({
+// id: data.identifier,
+// lng: parseFloat(coordinates[0]),
+// lat: parseFloat(coordinates[1]),
+// mag: parseFloat(data.info.magnitude),
+// depth: data.info.depth,
+// message: data.info.description + "\n" + data.info.instruction,
+// time: readAbleTime,
+// });
+// const ntg = new TitikGempa(nig.id, nig, {
+// map: map.current!,
+// showMarker: true
+// });
+
+// setTimeout(() => {
+
+// // setAlertGempaBumi(ntg);
+// setGempaDirasakan(ntg);
+// }, 6000);
+// } else if (!cek) {
+// tgs.current.push(new TitikGempa(nig.id, nig));
+// //sort by time
+// tgs.current.sort(function (a: any, b: any) {
+// return new Date(b.time).getTime() - new Date(a.time).getTime();
+// })
+// geoJsonTitikGempa.current.features.push({
+// "geometry": {
+// "type": "Point",
+// "coordinates": [
+// nig.lng,
+// nig.lat,
+// 1
+// ]
+// },
+// "type": "Feature",
+// "properties": {
+// id: nig.id,
+// depth: parseFloat(nig.depth.replaceAll(" Km", "")).toFixed(2),
+// mag: nig.mag,
+// time: nig.time,
+// place: nig.place,
+// }
+// });
+// (map.current!.getSource('earthquakes') as mapboxgl.GeoJSONSource).setData(geoJsonTitikGempa.current);
+// setEvents(tgs.current);
+
+// }
+
+// const ntg = new TitikGempa(nig.id, nig, {
+// map: map.current!
+// });
+// setGempaDirasakan(ntg);
+
+// // getGempaPeriodik();
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+
+
+// }
+
+// function getGempaKecil() {
+// if (lastGempaKecilId.current) {
+// return;
+// }
+// console.log("getGempaKecil");
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/lastQL.json?t=" + new Date().getTime();
+// fetch(url)
+// .then(response => response.json())
+// .then((data) => {
+// if (data.features.length > 0) {
+// const feature = data.features[0];
+// lastGempaKecilId.current = feature.properties.id;
+
+// const sentTime = DateTime.fromSQL(feature.properties.time, { zone: 'UTC' });
+// const currentTime = DateTime.now().setZone("UTC");
+
+// const msg = `${feature.properties.place}
+// Magnitudo : ${feature.properties.mag}
+// Kedalaman : ${feature.properties.depth}
+// Lokasi (Lat,Lng) :
+// ${feature.geometry.coordinates[0]} , ${feature.geometry.coordinates[1]}`;
+
+// const dt = DateTime.fromSQL(feature.properties.time, { zone: 'UTC' }).setZone("Asia/Jakarta");
+// const readAbleTime = dt.toISODate() + " " + dt.toLocaleString(DateTime.TIME_24_WITH_SECONDS)
+// const nig: InfoGempa = {
+// id: feature.properties.id,
+// lng: parseFloat(feature.geometry.coordinates[0]),
+// lat: parseFloat(feature.geometry.coordinates[1]),
+// mag: parseFloat(feature.properties.mag),
+// depth: feature.properties.depth || "10 Km",
+// message: msg,
+// place: feature.properties.place,
+// time: readAbleTime
+// };
+
+
+
+
+// //if sent time is less than 10 minutes
+// if ((currentTime.toMillis() - sentTime.toMillis()) < 600000) {
+
+// if (map.current) {
+// var notif = new Audio(smallEarthQuakeSound);
+// notif.play();
+// // map.current!.flyTo({
+// // center: [feature.geometry.coordinates[0], feature.geometry.coordinates[1]],
+// // zoom: 7,
+// // essential: true
+// // });
+
+// const tg = new TitikGempa(feature.properties.id, nig, {
+// pWaveSpeed: 6000,
+// sWaveSpeed: 3000,
+// map: map.current!,
+// description: msg,
+// zoomToPosition: true,
+// showMarker: true,
+// showPopup: true,
+// showPopUpInSecond: 1,
+// });
+
+// setGempaTerakhir(tg);
+// setAlertGempaBumi(new TitikGempa(feature.properties.id, nig));
+
+// }
+
+
+
+
+// } else {
+// setGempaTerakhir(new TitikGempa(feature.properties.id, nig));
+// }
+
+// const cek = tgs.current.find((v) => v.id == feature.properties.id);
+// if (!cek) {
+
+// tgs.current.unshift(new TitikGempa(feature.properties.id, nig));
+// geoJsonTitikGempa.current.features.push(feature);
+// (map.current!.getSource('earthquakes') as mapboxgl.GeoJSONSource).setData(geoJsonTitikGempa.current);
+
+
+// }
+
+
+// setEvents(tgs.current);
+
+
+
+
+// }
+// getGempaPeriodik();
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+// }
+
+// function getGempaPeriodik() {
+// setInterval(() => {
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/datagempa.json?t=" + new Date().getTime()
+// //await fetch
+// fetch(url)
+// .then(response => response.json())
+// .then((data) => {
+// if (lastGempaId.current != data.identifier) {
+// lastGempaId.current = data.identifier;
+// const coordinates = data.info.point.coordinates.split(",");
+// const sentTime = DateTime.fromISO(data.sent.replace("WIB", ""), { zone: "Asia/Jakarta" });
+// const readAbleTime = sentTime.toISODate() + " " + sentTime.toLocaleString(DateTime.TIME_24_WITH_SECONDS);
+
+// warningHandler({
+// id: data.identifier,
+// lng: parseFloat(coordinates[0]),
+// lat: parseFloat(coordinates[1]),
+// mag: parseFloat(parseFloat(data.info.magnitude).toFixed(1)),
+// depth: data.info.depth,
+// message: data.info.description + "\n" + data.info.instruction,
+// time: readAbleTime
+// });
+
+// if (data.info.wzarea != undefined && data.info.wzarea.length > 0) {
+// if (data.info.subject == "Warning Tsunami PD-4") {
+// //delete outline-costline layer
+// try {
+// map.current!.removeLayer('outline-coastline');
+// map.current!.removeLayer('outline');
+// } catch (error) {
+
+// }
+// } else if (data.info.subject.includes("Warning Tsunami")) {
+// warningTsunamiHandler(data.info);
+// }
+
+// }
+
+// }
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+// }, 5000);
+
+// setInterval(() => {
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/lastQL.json?t=" + new Date().getTime();
+// fetch(url)
+// .then(response => response.json())
+// .then((data) => {
+// const feature = data.features[0];
+// const msg = `${feature.properties.place}
+// Magnitudo : ${feature.properties.mag}
+// Kedalaman : ${feature.properties.depth}
+// Lokasi (Lat,Lng) :
+// ${feature.geometry.coordinates[0]} , ${feature.geometry.coordinates[1]}`;
+
+// const dt = DateTime.fromSQL(feature.properties.time, { zone: 'UTC' }).setZone("Asia/Jakarta");
+// const readAbleTime = dt.toISODate() + " " + dt.toLocaleString(DateTime.TIME_24_WITH_SECONDS)
+// const nig: InfoGempa = {
+// id: feature.properties.id,
+// lng: parseFloat(feature.geometry.coordinates[0]),
+// lat: parseFloat(feature.geometry.coordinates[1]),
+// mag: parseFloat(feature.properties.mag),
+// depth: feature.properties.depth || "10 Km",
+// message: msg,
+// place: feature.properties.place,
+// time: readAbleTime
+// };
+// if (lastGempaKecilId.current != feature.properties.id) {
+// lastGempaKecilId.current = feature.properties.id;
+// var notif = new Audio(smallEarthQuakeSound);
+// notif.play();
+// if (!map.current) return;
+
+
+// if (gempaTerakhir != null && gempaTerakhir.setting != null && gempaTerakhir.setting.map != null) {
+// gempaTerakhir.removeAllRender();
+// gempaTerakhir.removeMarker();
+// if (tgs.current.length > 0) {
+// const ig = tgs.current[0].infoGempa
+// geoJsonTitikGempa.current.features.push({
+// "geometry": {
+// "type": "Point",
+// "coordinates": [
+// ig.lng,
+// ig.lat,
+// 1
+// ]
+// },
+// "type": "Feature",
+// "properties": {
+// id: ig.id,
+// depth: ig.depth,
+// mag: ig.mag,
+// time: ig.time,
+// place: ig.place,
+// }
+// });
+// (map.current!.getSource('earthquakes') as mapboxgl.GeoJSONSource).setData(geoJsonTitikGempa.current);
+// }
+// }
+
+// tgs.current.push(new TitikGempa(nig.id, nig, {
+// map: map.current!,
+// zoomToPosition: true,
+// showMarker: true,
+// showPopup: true,
+// showPopUpInSecond: 1
+// }))
+// tgs.current.sort(function (a: any, b: any) {
+// return new Date(b.time).getTime() - new Date(a.time).getTime();
+// });
+// setEvents(tgs.current);
+// setAlertGempaBumi(new TitikGempa(nig.id, nig))
+
+// const tg = new TitikGempa(lastGempaKecilId.current, nig, {
+// pWaveSpeed: 6000,
+// sWaveSpeed: 3000,
+// map: map.current!,
+// description: msg,
+// });
+
+// // titikGempaKecil.current = tg;
+// setGempaTerakhir(new TitikGempa(nig.id, nig));
+// } else {
+// const cek = tgs.current.find((v) => v.id == feature.properties.id);
+// if (cek && cek.infoGempa.mag != parseFloat(feature.properties.mag)) {
+// console.log(cek.infoGempa.mag, parseFloat(feature.properties.mag))
+// setGempaTerakhir(new TitikGempa(nig.id, nig));
+// setAlertGempaBumi(new TitikGempa(nig.id, nig));
+// const indextgs = tgs.current.findIndex((v) => v.id == feature.properties.id);
+// tgs.current[indextgs].infoGempa = nig;
+
+// }
+// }
+
+
+// })
+// .catch((error) => {
+// console.error('Error initializing socket:', error);
+// });
+// }, 5000);
+// }
+
+// const selectedPopup = useRef(null);
+
+// function selectEvent(d: InfoGempa) {
+// setDetailInfoGempa(d);
+// if (selectedPopup.current) {
+// selectedPopup.current.remove();
+// }
+
+// map.current!.flyTo({
+// center: [d.lng, d.lat],
+// zoom: 6,
+// essential: true
+// });
+// const placeholder = document.createElement('div');
+// const root = createRoot(placeholder)
+// root.render(
+//
+//
+//
+// } className='min-h-48 min-w-48 whitespace-pre-wrap ' >
+//
+// -
+// Magnitudo : {d.mag}
+//
+// -
+// Kedalaman : {d.depth}
+//
+// -
+// Waktu : {new Date(d.time!).toLocaleString()}
+//
+// -
+// Lokasi (Lat,Lng) :
{d.lat} , {d.lng}
+//
+//
+// );
+
+// selectedPopup.current = new AnimatedPopup({
+// closeOnClick: false,
+// openingAnimation: {
+// duration: 100,
+// easing: 'easeOutSine',
+// transform: 'scale'
+// },
+// closingAnimation: {
+// duration: 100,
+// easing: 'easeInOutSine',
+// transform: 'scale'
+// }
+// }).setDOMContent(placeholder).setLngLat([d.lng, d.lat]).addTo(map.current!);
+// const cekTable = document.querySelector("#histori_tabel tbody");
+// if (cekTable) {
+// cekTable.innerHTML = "
";
+// }
+// setTimeout(() => {
+// readTextFile("https://bmkg-content-inatews.storage.googleapis.com/history." + d.id + ".txt");
+// }, 500);
+// }
+
+// function testDemoGempa() {
+// if (geoJsonData.current == null) {
+// alert("Wait loading geojson");
+// return;
+// };
+// const bbox = turf.bbox(geoJsonData.current);
+// const randomPosition = turf.randomPosition(bbox);
+// const mag = (Math.random() * (10 - 5) + 5).toFixed(1);
+// const depth = (Math.random() * 20).toFixed(1) + " Km";
+// const message = "Gempa Bumi Test Pada Lokasi : Lat : " + randomPosition[1].toFixed(4) + " Lng : " + randomPosition[0].toFixed(4) + " Magnitudo : " + mag + " Kedalaman : " + depth;
+// const id = `tg-${new Date().getTime()}`;
+
+// const dt = DateTime.now();
+// const readAbleTime = dt.toISODate() + " " + dt.toLocaleString(DateTime.TIME_24_WITH_SECONDS)
+// const nig: InfoGempa = {
+// id: id,
+// lng: randomPosition[0].toFixed(4),
+// lat: randomPosition[1].toFixed(4),
+// mag: parseFloat(mag),
+// depth: depth || "10 Km",
+// message: message,
+// time: readAbleTime
+// };
+
+
+// warningHandler(nig);
+
+// // setTimeout(() => {
+// // setInfoGempaDirasakanTerakhir(nig);
+// // }, 6000);
+
+// }
+
+// function testDemoTsunami() {
+// const url = "https://bmkg-content-inatews.storage.googleapis.com/last30tsunamievent.xml";
+// //fecth and parse xml
+// fetch(url)
+// .then(response => response.text())
+// .then(data => {
+// const parser = new XMLParser();
+// let jObj = parser.parse(data);
+// var infos = jObj.alert.info;
+// infos = infos.filter((v) => v.wzarea != undefined)
+// var randInfo = infos[(Math.random() * infos.length) | 0]
+
+// warningTsunamiHandler(randInfo);
+
+// }).catch((error) => {
+// alert("Failed load geojson data : " + error);
+// console.error('Error fetching data:', error);
+// });
+
+// //warningTsunamiHandler(null);
+// }
+
+// function readTextFile(e: string) {
+
+// var t = new XMLHttpRequest;
+// t.open("GET", e, !1), t.onreadystatechange = function () {
+// if (4 === t.readyState && (200 === t.status || 0 == t.status)) {
+// let u = t.responseText.split("\n");
+// var table = document.getElementById("histori_tabel") as HTMLTableElement;
+// //clear tbody
+
+// let T = u.length - 1;
+// for (let t = 1; t < T; t++) {
+// let T = u[t].split("|");
+// var n = table.insertRow(t),
+// a = n.insertCell(0),
+// l = n.insertCell(1),
+// s = n.insertCell(2),
+// i = n.insertCell(3),
+// o = n.insertCell(4),
+// r = n.insertCell(5),
+// d = n.insertCell(6),
+// m = n.insertCell(7),
+// g = n.insertCell(8),
+// c = n.insertCell(9);
+// a.innerHTML = T[0], l.innerHTML = T[1], s.innerHTML = T[2], i.innerHTML = T[3], o.innerHTML = T[4], r.innerHTML = T[5], d.innerHTML = T[6], m.innerHTML = T[7], g.innerHTML = T[8], c.innerHTML = T[9]
+// }
+// }
+// }, t.send(null)
+// }
+
+// function generateDiv(max) {
+// let arrayDivs: any = [];
+// for (let index = 0; index < max; index++) {
+// arrayDivs.push(
+//

+//
);
+// }
+
+// return arrayDivs;
+// }
+
+
+// return (
+//
+//
+
+//
+
+// {!loadingScreen && alertGempaBumi &&
+//
+//
+//
+//
+// } className='hidden md:block show-pop-up fixed top-12 md:top-6 left-0 card-float right-0 md:left-6 md:w-1/3 lg:w-1/4 xl:w-1/5 2xl:w-1/6'>
+//
+//
+//
+//
+//
+//
{alertGempaBumi.readableMag}
+//
MAG
+//
+//
+//
+//
DEPTH : {alertGempaBumi.readableDepth} KM
+//
+//
+//
+//
+
+//
+// TIME |
+// {alertGempaBumi.readableTime} WIB |
+//
+//
+// MAG |
+// {alertGempaBumi.mag} |
+//
+//
+// DEPTH |
+// {alertGempaBumi.depth} |
+//
+//
+// LAT |
+// {alertGempaBumi.infoGempa.lat} |
+//
+//
+// LNG |
+// {alertGempaBumi.infoGempa.lng} |
+//
+//
+//
+//
+
+//
+//
+//
{alertGempaBumi.infoGempa.message}
+//
+//
+// {alertGempaBumi.mag >= 5 &&
+//
+// {alertGempaBumi.infoGempa.listKotaTerdampak && alertGempaBumi.infoGempa.listKotaTerdampak.map((kota, i) => {
+// if (kota.hit) {
+// return -
+//
+//
+// } else {
+// return -
+//
+//
+// }
+// })}
+//
+//
}
+// }
+
+// {!loadingScreen && infoTsunami &&
+//
+//
+//
+//
PERINGATAN TSUNAMI
+//
+//
+// }
+// footer={
+//
+// {infoTsunami.infoTsunami.level}
+//
+// }
+// className='hidden md:block show-pop-up fixed top-12 md:top-6 left-0 card-float right-0 md:left-6 md:w-1/3 lg:w-1/4 xl:w-1/5 2xl:w-1/6'>
+//
+
+//
+//
{infoTsunami.infoTsunami.message}
+//
+//
+// {(infoTsunami.infoTsunami.level?.includes("PD-1") || infoTsunami.infoTsunami.level?.includes("PD-2")) &&
+//
+// {infoTsunami.infoTsunami.listKotaTerdampak && infoTsunami.infoTsunami.listKotaTerdampak.map((kota, i) => {
+// return -
+//
+//
+// })}
+//
+//
}
+// }
+
+//
+//
+
+//
+//
+
+
+
+// {!loadingScreen && EVENT LOG
+// } className=' fixed right-0 md:right-6 top-1 md:top-6 card-float md:w-1/3 lg:w-1/5 show-pop-up'>
+//
+
+// }
+
+
+
+
+
+// {!loadingScreen && gempaTerakhir &&
+//
+// GEMPA TERDETEKSI TERAKHIR
+//
+
+//
+// }
+// footer={
+// {
+// selectEvent(gempaTerakhir.infoGempa);
+// }}>
+//
+//
+// }
+
+// className='hidden md:block show-pop-up fixed bottom-28 md:bottom-6 card-float left-1 right-1 m-auto md:w-1/4 lg:w-1/6'>
+//
+//
+//
+//
+// PLACE |
+// {gempaTerakhir.infoGempa.place} |
+//
+//
+// TIME |
+// {gempaTerakhir.readableTime} WIB |
+//
+//
+// MAG |
+// {gempaTerakhir.infoGempa.mag} |
+//
+//
+// DEPTH |
+// {gempaTerakhir.readableDepth} KM |
+//
+//
+// LAT |
+// {gempaTerakhir.infoGempa.lat} |
+//
+//
+// LNG |
+// {gempaTerakhir.infoGempa.lng} |
+//
+//
+//
+//
+// }
+
+// {!loadingScreen && gempaDirasakan &&
+//
+// GEMPA DIRASAKAN TERAKHIR
+//
+
+//
+// }
+// footer={
+// {
+// selectEvent(gempaDirasakan.infoGempa);
+// }}>
+//
+//
+// }
+
+// className='hidden md:block show-pop-up fixed bottom-10 left-1 right-1 md:right-0 md:left-6 card-float md:w-1/3 lg:w-1/4 xl:w-1/5 2xl:w-1/6'>
+//
+//
+//
+//
+//
+//
{gempaDirasakan.readableMag}
+//
MAG
+//
+//
+//
+//
DEPTH : {gempaDirasakan.readableDepth} KM
+//
+//
+//
+//
+
+//
+// TIME |
+// {gempaDirasakan.infoGempa.time} WIB |
+//
+//
+// MAG |
+// {gempaDirasakan.infoGempa.mag} |
+//
+//
+// DEPTH |
+// {gempaDirasakan.infoGempa.depth} |
+//
+//
+// LAT |
+// {gempaDirasakan.infoGempa.lat} |
+//
+//
+// LNG |
+// {gempaDirasakan.infoGempa.lng} |
+//
+//
+//
+//
+
+//
+//
+//
{gempaDirasakan.infoGempa.message}
+//
+//
+// }
+
+// {!loadingScreen && detailInfoGempa &&
+//
+// DETAIL EVENT
+//
+//
+//
+// }
+// className='right-6 bottom-10 md:bottom-6 fixed card-float show-pop-up '>
+//
+//
+// {/*

*/}
+
+//
+//
+//
+//
+//
+// PLACE |
+// {detailInfoGempa.place} |
+//
+//
+// TIME |
+// {detailInfoGempa.time} WIB |
+//
+//
+// MAG |
+// {detailInfoGempa.mag} |
+//
+//
+// DEPTH |
+// {parseFloat(detailInfoGempa.depth.replace(" Km", "")).toFixed(2)} KM |
+//
+//
+// LAT |
+// {detailInfoGempa.lat} |
+//
+//
+// LNG |
+// {detailInfoGempa.lng} |
+//
+//
+//
+//
+//
+
+//
+//
+//
+//
+//
+// Time(UTC)
+// |
+//
+// +OT(min)
+// |
+//
+// Lat
+// |
+//
+// Lng
+// |
+//
+// Depth
+// |
+//
+// Phase
+// |
+//
+// MagType
+// |
+//
+// Mag
+// |
+//
+// MagCount
+// |
+//
+// Status
+// |
+//
+//
+//
+//
+// |
+//
+//
+//
+//
+//
+
+//
+
+// }
+
+// {!loadingScreen && alertGempaBumi && gempaDirasakan &&
+//
+//
+//
+// } className='block md:hidden show-pop-up fixed bottom-10 md:top-6 left-0 card-warning right-0 md:left-6 md:w-1/4 lg:w-1/5'>
+//
+//
+//
+//
+//
+//
{gempaDirasakan.readableMag}
+//
MAG
+//
+//
+//
+//
DEPTH : {gempaDirasakan.readableDepth} KM
+//
+//
+//
+//
+
+//
+// TIME |
+// {gempaDirasakan.infoGempa.time} WIB |
+//
+//
+// MAG |
+// {gempaDirasakan.infoGempa.mag} |
+//
+//
+// DEPTH |
+// {gempaDirasakan.infoGempa.depth} |
+//
+//
+// LAT |
+// {gempaDirasakan.infoGempa.lat} |
+//
+//
+// LNG |
+// {gempaDirasakan.infoGempa.lng} |
+//
+//
+//
+//
+
+//
+//
+//
{gempaDirasakan.infoGempa.message}
+//
+//
+
+// }
+
+// {!loadingScreen && alertGempaBumis.map((v, i) => {
+// return
+//
+//
+// })}
+
+// {/* {!loadingScreen && alertGempaBumi && } */}
+
+
+//
+
+// {!loadingScreen && alertTsunami &&
+
+//
+//
+//
+// {generateDiv(window.screen.width + (window.screen.width / 3))}
+
+//
+//
+//
+
+//
+//
+//
+//
+//
+//
+// TSUNAMI
+// Peringatan Dini Tsunami
+//
+//
+//
+//
+//
+
+//
+//
+//
+
+//
+//
+//
+//
+//
+//
+//
{alertTsunami.infoTsunami.level}
+//
+//
+// }
+// className='w-full h-auto'>
+//
+// {alertTsunami.infoTsunami.message}
+//
+//
+//
+
+//
+//
+
+
+
+//
+//
+//
+
+//
+
+//
+
+
+//
+
+//
+
+//
+
+
+
+//
+
+
+
+// }
+
+
+//
+//
+//
INI MERUPAKAN DESAIN KONSEP - DATA GEMPA DARI BMKG
+//
+
+//
+
+// );
+// }
diff --git a/sigap-website/app/_components/map/controls/panic-button-demo.tsx b/sigap-website/app/_components/map/controls/panic-button-demo.tsx
new file mode 100644
index 0000000..4781e18
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/panic-button-demo.tsx
@@ -0,0 +1,108 @@
+"use client"
+
+import { useState } from 'react';
+import { Button } from '@/app/_components/ui/button';
+import {
+ AlertTriangle,
+ Bell,
+ ShieldAlert,
+ Radio,
+ RadioTower,
+ Shield
+} from 'lucide-react';
+import { cn } from '@/app/_lib/utils';
+import { Badge } from '@/app/_components/ui/badge';
+import { IIncidentLog } from '@/app/_utils/types/ews';
+
+interface PanicButtonDemoProps {
+ onTriggerAlert: (priority: 'high' | 'medium' | 'low') => void;
+ onResolveAllAlerts: () => void;
+ activeIncidents: IIncidentLog[];
+ className?: string;
+}
+
+export default function PanicButtonDemo({
+ onTriggerAlert,
+ onResolveAllAlerts,
+ activeIncidents,
+ className
+}: PanicButtonDemoProps) {
+ const [isTriggering, setIsTriggering] = useState(false);
+
+ const handleTriggerPanic = (priority: 'high' | 'medium' | 'low') => {
+ setIsTriggering(true);
+ onTriggerAlert(priority);
+
+ // Reset animation
+ setTimeout(() => {
+ setIsTriggering(false);
+ }, 1000);
+ };
+
+ return (
+
+
+
+
+ EWS Panic Button Demo
+
+
+ {activeIncidents.length > 0 && (
+
+ {activeIncidents.length} Active
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ {activeIncidents.length > 0 && (
+
+ )}
+
+
+
+ Simulates a mobile app panic button activation in the Jember area.
+
+
+ );
+}
diff --git a/sigap-website/app/_components/map/crime-map.tsx b/sigap-website/app/_components/map/crime-map.tsx
index 5d082e9..59e4831 100644
--- a/sigap-website/app/_components/map/crime-map.tsx
+++ b/sigap-website/app/_components/map/crime-map.tsx
@@ -42,6 +42,7 @@ export default function CrimeMap() {
const [showUnclustered, setShowUnclustered] = useState(true)
const [useAllYears, setUseAllYears] = useState(false)
const [useAllMonths, setUseAllMonths] = useState(false)
+ const [showEWS, setShowEWS] = useState(true)
const mapContainerRef = useRef(null)
@@ -185,6 +186,9 @@ export default function CrimeMap() {
setUseAllYears(false);
setUseAllMonths(false);
}
+
+ // Enable EWS in all modes for demo purposes
+ setShowEWS(true);
}
const showTimelineLayer = activeControl === "timeline";
@@ -218,87 +222,90 @@ export default function CrimeMap() {
) : (
-
+
-
-
+
+
+
- {isFullscreen && (
- <>
-
-
-
-
-
- {isFullscreen && (
-
- {showClusters && (
-
- )}
- {showUnclustered && !showClusters && (
-
- )}
-
- )}
-
- {isFullscreen && showUnitsLayer && (
-
-
+
+
- )}
- {isFullscreen && showTimelineLayer && (
-
-
-
- )}
- >
- )}
+
+ {isFullscreen && (
+
+ {showClusters && (
+
+ )}
+ {showUnclustered && !showClusters && (
+
+ )}
+
+ )}
- {isFullscreen && (
-
-
-
- )}
-
+ {isFullscreen && showUnitsLayer && (
+
+
+
+ )}
+
+ {isFullscreen && showTimelineLayer && (
+
+
+
+ )}
+ >
+ )}
+
+ {isFullscreen && (
+
+
+
+ )}
+
+
)}
diff --git a/sigap-website/app/_components/map/layers/coastline.tsx b/sigap-website/app/_components/map/layers/coastline.tsx
index 98b8c37..3a22df9 100644
--- a/sigap-website/app/_components/map/layers/coastline.tsx
+++ b/sigap-website/app/_components/map/layers/coastline.tsx
@@ -14,40 +14,50 @@ export default function CoastlineLayer({ map, visible = true }: CoastlineLayerPr
// Function to add coastline layer
function addCoastline() {
- const sourceId = 'coastline';
+ const sourceId = 'coastline_id';
const layerId = 'outline-coastline';
// Make sure map is defined
if (!map) return;
try {
- // Check if the source already exists
- if (!map.getSource(sourceId)) {
+ // More robust check if the source already exists
+ let sourceExists = false;
+ try {
+ sourceExists = !!map.getSource(sourceId);
+ } catch (e) {
+ sourceExists = false;
+ }
+
+ if (!sourceExists) {
// Add coastline data source
fetch('/geojson/garis_pantai.geojson')
.then(response => response.json())
.then(data => {
- // Add coastline data source
- map.addSource(sourceId, {
- type: 'geojson',
- generateId: true,
- data: data
- });
+ // Double-check the source doesn't exist right before adding
+ if (!map.getSource(sourceId)) {
+ // Add coastline data source
+ map.addSource(sourceId, {
+ type: 'geojson',
+ generateId: true,
+ data: data
+ });
- // Add coastline layer
- map.addLayer({
- 'id': layerId,
- 'type': 'line',
- 'source': sourceId,
- 'layout': {
- 'visibility': visible ? 'visible' : 'none',
- },
- 'paint': {
- 'line-color': ['get', 'color'],
- 'line-width': 5,
- 'line-opacity': 1
- }
- });
+ // Add coastline layer
+ map.addLayer({
+ 'id': layerId,
+ 'type': 'line',
+ 'source': sourceId,
+ 'layout': {
+ 'visibility': visible ? 'visible' : 'none',
+ },
+ 'paint': {
+ 'line-color': '#1a1a1a', // dull white color instead of ['get', 'color']
+ 'line-width': 5,
+ 'line-opacity': 1
+ }
+ });
+ }
})
.catch((error) => {
console.error('Error fetching coastline data:', error);
@@ -71,7 +81,7 @@ export default function CoastlineLayer({ map, visible = true }: CoastlineLayerPr
if (!map || !map.getStyle()) return;
const layerId = 'outline-coastline';
- const sourceId = 'coastline';
+ const sourceId = 'coastline_id';
if (map.getLayer(layerId)) {
map.removeLayer(layerId);
@@ -92,14 +102,24 @@ export default function CoastlineLayer({ map, visible = true }: CoastlineLayerPr
if (map.loaded() && map.isStyleLoaded()) {
addCoastline();
} else {
- // Use multiple events to catch map ready state
- map.on('load', addCoastline);
- map.on('style.load', addCoastline);
- map.on('styledata', addCoastline);
+ // Reduce event listeners to minimize duplicates
+ const addLayerOnce = () => {
+ // Remove all listeners after first successful execution
+ map.off('load', addLayerOnce);
+ map.off('style.load', addLayerOnce);
+ map.off('styledata', addLayerOnce);
+ clearTimeout(timeoutId);
+
+ addCoastline();
+ };
+
+ map.on('load', addLayerOnce);
+ map.on('style.load', addLayerOnce);
+ map.on('styledata', addLayerOnce);
// Fallback timeout
timeoutId = setTimeout(() => {
- addCoastline();
+ addLayerOnce();
}, 2000);
}
} catch (error) {
diff --git a/sigap-website/app/_components/map/layers/ews-alert-layer.tsx b/sigap-website/app/_components/map/layers/ews-alert-layer.tsx
new file mode 100644
index 0000000..cf06de0
--- /dev/null
+++ b/sigap-website/app/_components/map/layers/ews-alert-layer.tsx
@@ -0,0 +1,318 @@
+"use client"
+
+import { useEffect, useState, useRef } from 'react';
+import mapboxgl from 'mapbox-gl';
+import { IIncidentLog, EWSStatus } from '@/app/_utils/types/ews';
+import { createRoot } from 'react-dom/client';
+import { AlertTriangle, X } from 'lucide-react';
+import DigitalClock from '../markers/digital-clock';
+import { Badge } from '@/app/_components/ui/badge';
+import { Button } from '@/app/_components/ui/button';
+
+interface EWSAlertLayerProps {
+ map: mapboxgl.Map | null;
+ incidents?: IIncidentLog[];
+ onIncidentResolved?: (id: string) => void;
+ visible?: boolean;
+}
+
+export default function EWSAlertLayer({
+ map,
+ incidents = [],
+ onIncidentResolved,
+ visible = true
+}: EWSAlertLayerProps) {
+ const [ewsStatus, setEwsStatus] = useState
('idle');
+ const [activeIncidents, setActiveIncidents] = useState([]);
+ const markersRef = useRef