diff --git a/sigap-website/app/protected/(admin-pages)/dashboard/page.tsx b/sigap-website/app/protected/(admin-pages)/dashboard/page.tsx index 2b29bcc..590c3c3 100644 --- a/sigap-website/app/protected/(admin-pages)/dashboard/page.tsx +++ b/sigap-website/app/protected/(admin-pages)/dashboard/page.tsx @@ -14,7 +14,7 @@ import { SidebarTrigger, } from "@/components/ui/sidebar"; -export default function Page() { +export default function Dashboard() { return ( <>
diff --git a/sigap-website/app/protected/(admin-pages)/map/page.tsx b/sigap-website/app/protected/(admin-pages)/map/page.tsx new file mode 100644 index 0000000..0625219 --- /dev/null +++ b/sigap-website/app/protected/(admin-pages)/map/page.tsx @@ -0,0 +1,50 @@ +import { AppSidebar } from "@/components/app-sidebar"; +import { MapboxMap } from "@/components/map/mapbox-view"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { Separator } from "@/components/ui/separator"; +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/components/ui/sidebar"; + +export default function Map() { + return ( + <> +
+
+ + + + + + Sigap - v + + + + Map + + + +
+
+
+
+ +
+
+
+
+
+
+
+ + ); +} diff --git a/sigap-website/components/app-sidebar.tsx b/sigap-website/components/app-sidebar.tsx index d3ed682..9462c6c 100644 --- a/sigap-website/components/app-sidebar.tsx +++ b/sigap-website/components/app-sidebar.tsx @@ -22,7 +22,10 @@ import { SidebarHeader, SidebarRail, } from "@/components/ui/sidebar"; -import { NavItemsGet } from "@/src/applications/entities/models/nav-items.model"; +import { + NavItemsGet, + NavSubItems, +} from "@/src/applications/entities/models/nav-items.model"; import { getNavItems } from "@/actions/dashboard/nav-items"; import DynamicIcon, { DynamicIconProps } from "./dynamic-icon"; @@ -98,7 +101,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { }; // ⚡ Fungsi untuk membandingkan dua objek secara deep - const isDataEqual = (data1: any, data2: any): boolean => + const isDataEqual = (data1: NavItemsGet, data2: NavItemsGet): boolean => JSON.stringify(data1) === JSON.stringify(data2); useEffect(() => { @@ -117,7 +120,10 @@ export function AppSidebar({ ...props }: React.ComponentProps) { const currentStoredData = loadNavItemsFromStorage(); // 🔄 Jika data berbeda, update localStorage dan state - if (!isDataEqual(currentStoredData, fetchedData)) { + if ( + currentStoredData && + !isDataEqual(currentStoredData, fetchedData) + ) { localStorage.setItem( NAV_ITEMS_STORAGE_KEY, JSON.stringify(fetchedData) @@ -149,6 +155,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { items: item.sub_items.map((subItem) => ({ title: subItem.title, url: subItem.url, + icon: subItem.icon, isActive: subItem.is_active, })), })); @@ -159,7 +166,13 @@ export function AppSidebar({ ...props }: React.ComponentProps) { ({ ...item, - icon: () => , + icon: () => , + items: item.items.map((subItem: NavSubItems) => ({ + ...subItem, + icon: () => ( + + ), + })), }))} /> ); @@ -179,7 +192,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { ) : ( )} - + {/* */} diff --git a/sigap-website/components/dynamic-icon.tsx b/sigap-website/components/dynamic-icon.tsx index 8a28ee7..eceff9a 100644 --- a/sigap-website/components/dynamic-icon.tsx +++ b/sigap-website/components/dynamic-icon.tsx @@ -22,8 +22,8 @@ const DynamicIcon: React.FC = ({ iconName, size = 32, color, - className = "IconAlertHexagon", - stroke, + className = "", // Empty string default, not an icon name + stroke, // This will be passed as strokeWidth }) => { // Safety check: Ensure the iconName exists in TablerIcons if (!(iconName in TablerIcons)) { @@ -37,7 +37,7 @@ const DynamicIcon: React.FC = ({ size?: number; color?: string; className?: string; - stroke?: number; + strokeWidth?: number; // Correct prop name for Tabler icons }>; return ( @@ -45,9 +45,9 @@ const DynamicIcon: React.FC = ({ size={size} color={color} className={className} - stroke={stroke} + strokeWidth={stroke} // Pass stroke as strokeWidth /> ); }; -export default DynamicIcon; +export default DynamicIcon; \ No newline at end of file diff --git a/sigap-website/components/map/mapbox-view.tsx b/sigap-website/components/map/mapbox-view.tsx new file mode 100644 index 0000000..fe4841d --- /dev/null +++ b/sigap-website/components/map/mapbox-view.tsx @@ -0,0 +1,105 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import mapboxgl from "mapbox-gl"; +import "mapbox-gl/dist/mapbox-gl.css"; +import { Button } from "@react-email/components"; +import { IconMapPin } from "@tabler/icons-react"; + +// You should store this in an environment variable +const MAPBOX_ACCESS_TOKEN = + process.env.SIGAP_MAPBOX_ACCESS_TOKEN || + "pk.eyJ1IjoiZGl5b2FuZ2dhcmEiLCJhIjoiY203ZG5rcjhzMDA4djJqcXpzMXpoZzh6cSJ9.ZMiOrYWSYsabmZp3lnI5xw"; + +mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN; + +export const MapboxMap = () => { + const mapContainer = useRef(null); + const map = useRef(null); + const [lng, setLng] = useState(113.7025); + const [lat, setLat] = useState(-8.1725); + const [zoom, setZoom] = useState(10); + + useEffect(() => { + if (map.current) return; // initialize map only once + if (!mapContainer.current) return; // wait for map container to be ready + + // Set the bounds to Kabupaten Jember + const bounds: mapboxgl.LngLatBoundsLike = [ + [113.0, -8.5], // Southwest coordinates + [114.0, -7.5], // Northeast coordinates + ]; + + map.current = new mapboxgl.Map({ + container: mapContainer.current, + style: "mapbox://styles/mapbox/streets-v12", + center: [lng, lat], + zoom: zoom, + }); + + // Add zoom and rotation controls to the map (top-right corner) + map.current.addControl(new mapboxgl.NavigationControl(), "top-right"); + + // Add fullscreen control to the map (top-left corner) + map.current.addControl(new mapboxgl.FullscreenControl(), "top-left"); + + // Add control to focus on Jember (top-left corner) + // const focusButton = document.createElement("button"); + // focusButton.className = "mapboxgl-ctrl-icon"; + // focusButton.title = "Focus on Jember"; + // focusButton.innerHTML = ` + // + // + // + // `; + // focusButton.onclick = () => { + // focusButton; + // }; + + // map.current.addControl( + // { + // onAdd: () => focusButton, + // onRemove: () => focusButton.remove(), + // }, + // "top-left" + // ); + + map.current.on("move", () => { + if (!map.current) return; + setLng(Number(map.current.getCenter().lng.toFixed(4))); + setLat(Number(map.current.getCenter().lat.toFixed(4))); + setZoom(Number(map.current.getZoom().toFixed(2))); + }); + + return () => { + if (map.current) { + map.current.remove(); + } + }; + }, []); + + const focusOnJember = () => { + if (map.current) { + const bounds: mapboxgl.LngLatBoundsLike = [ + [113.0, -8.5], // Southwest coordinates + [114.0, -7.5], // Northeast coordinates + ]; + map.current.fitBounds(bounds, { padding: 20 }); + } + }; + + return ( +
+
+
+ Longitude: {lng} | Latitude: {lat} | Zoom: {zoom} +
+ {/* */} +
+ ); +}; diff --git a/sigap-website/components/nav-main.tsx b/sigap-website/components/nav-main.tsx index 1d71af1..f75b873 100644 --- a/sigap-website/components/nav-main.tsx +++ b/sigap-website/components/nav-main.tsx @@ -18,19 +18,22 @@ import { SidebarMenuSubItem, } from "@/components/ui/sidebar" +import * as TablerIcons from "@tabler/icons-react"; + export function NavMain({ items, }: { items: { - title: string - url: string - icon?: LucideIcon - isActive?: boolean + title: string; + url: string; + icon?: TablerIcons.Icon; + isActive?: boolean; items?: { - title: string - url: string - }[] - }[] + title: string; + icon?: TablerIcons.Icon; + url: string; + }[]; + }[]; }) { return ( @@ -44,19 +47,29 @@ export function NavMain({ className="group/collapsible" > - - - {item.icon && } - {item.title} - + {item.items && item.items.length > 0 ? ( + + + {item.icon && } + {item.title} + + + + ) : ( + + + {item.icon && } + {item.title} + - + )} {item.items?.map((subItem) => ( - + + {subItem.icon && } {subItem.title} @@ -69,5 +82,5 @@ export function NavMain({ ))} - ) + ); } diff --git a/sigap-website/package-lock.json b/sigap-website/package-lock.json index 0995860..2075005 100644 --- a/sigap-website/package-lock.json +++ b/sigap-website/package-lock.json @@ -32,6 +32,7 @@ "clsx": "^2.1.1", "input-otp": "^1.4.2", "lucide-react": "^0.468.0", + "mapbox-gl": "^3.10.0", "next": "latest", "next-themes": "^0.4.3", "prettier": "^3.3.3", @@ -1342,6 +1343,56 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-3.0.0.tgz", + "integrity": "sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==", + "license": "BSD-3-Clause" + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@next/env": { "version": "15.1.7", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.7.tgz", @@ -2990,6 +3041,38 @@ "@types/node": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "license": "MIT" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, "node_modules/@types/node": { "version": "22.10.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", @@ -2999,6 +3082,12 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "license": "MIT" + }, "node_modules/@types/phoenix": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", @@ -3025,6 +3114,15 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/ws": { "version": "8.5.14", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", @@ -3426,6 +3524,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/cheap-ruler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-4.0.0.tgz", + "integrity": "sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==", + "license": "ISC" + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3661,6 +3765,12 @@ "node": ">= 8" } }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3839,6 +3949,12 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/earcut": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz", + "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==", + "license": "ISC" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4191,6 +4307,12 @@ "node": ">=6.9.0" } }, + "node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -4200,6 +4322,12 @@ "node": ">=6" } }, + "node_modules/gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", + "license": "MIT" + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -4243,6 +4371,12 @@ "node": ">=4" } }, + "node_modules/grid-index": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", + "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", + "license": "ISC" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4319,7 +4453,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, "funding": [ { "type": "github", @@ -4563,6 +4696,12 @@ "node": ">=6" } }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, "node_modules/leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", @@ -4643,6 +4782,46 @@ "dev": true, "license": "ISC" }, + "node_modules/mapbox-gl": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.10.0.tgz", + "integrity": "sha512-YnQxjlthuv/tidcxGYU2C8nRDVXMlAHa3qFhuOJeX4AfRP72OMRBf9ApL+M+k5VWcAXi2fcNOUVgphknjLumjA==", + "license": "SEE LICENSE IN LICENSE.txt", + "workspaces": [ + "src/style-spec", + "test/build/typings" + ], + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^3.0.0", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@types/geojson": "^7946.0.16", + "@types/geojson-vt": "^3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/mapbox__vector-tile": "^1.3.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "cheap-ruler": "^4.0.0", + "csscolorparser": "~1.0.3", + "earcut": "^3.0.0", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.3", + "grid-index": "^1.1.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "serialize-to-js": "^3.1.2", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0", + "vt-pbf": "^3.1.3" + } + }, "node_modules/marked": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/marked/-/marked-7.0.4.tgz", @@ -4785,6 +4964,12 @@ "dev": true, "license": "MIT" }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -5140,6 +5325,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/pbf": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, "node_modules/peberminta": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", @@ -5336,6 +5534,12 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/potpack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==", + "license": "ISC" + }, "node_modules/prettier": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", @@ -5428,6 +5632,12 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "license": "ISC" }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5449,6 +5659,12 @@ ], "license": "MIT" }, + "node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -5987,6 +6203,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -6113,6 +6338,15 @@ "node": ">=10" } }, + "node_modules/serialize-to-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/serialize-to-js/-/serialize-to-js-3.1.2.tgz", + "integrity": "sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/sharp": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", @@ -6505,6 +6739,15 @@ "npm": ">=8" } }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6641,6 +6884,12 @@ "node": ">=0.8" } }, + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6841,6 +7090,17 @@ "node": ">= 0.8" } }, + "node_modules/vt-pbf": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "0.1.0", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", diff --git a/sigap-website/package.json b/sigap-website/package.json index 2cdd8d5..4046b26 100644 --- a/sigap-website/package.json +++ b/sigap-website/package.json @@ -33,6 +33,7 @@ "clsx": "^2.1.1", "input-otp": "^1.4.2", "lucide-react": "^0.468.0", + "mapbox-gl": "^3.10.0", "next": "latest", "next-themes": "^0.4.3", "prettier": "^3.3.3", diff --git a/sigap-website/prisma/schema.prisma b/sigap-website/prisma/schema.prisma index 93e487d..2506c55 100644 --- a/sigap-website/prisma/schema.prisma +++ b/sigap-website/prisma/schema.prisma @@ -105,6 +105,8 @@ model NavSubItems { @@map("nav_sub_items") } + + enum Role { admin staff