diff --git a/frontend/src/layouts/dashboard/config.js b/frontend/src/layouts/dashboard/config.js
index 171482a..f2e7fff 100644
--- a/frontend/src/layouts/dashboard/config.js
+++ b/frontend/src/layouts/dashboard/config.js
@@ -35,15 +35,15 @@ export const items = [
//
// )
// },
- // {
- // title: 'Map',
- // path: '/map',
- // icon: (
- //
- //
- //
- // ),
- // },
+ {
+ title: 'Map',
+ path: '/map',
+ icon: (
+
+
+
+ ),
+ },
{
title: 'Credentials',
path: '/credentials',
diff --git a/frontend/src/layouts/dashboard/side-nav.js b/frontend/src/layouts/dashboard/side-nav.js
index ce2e646..e378c2a 100644
--- a/frontend/src/layouts/dashboard/side-nav.js
+++ b/frontend/src/layouts/dashboard/side-nav.js
@@ -112,6 +112,9 @@ export const SideNav = (props) => {
}}
>
{items.map((item) => {
+ if (item.title == "Map" && process.env.NEXT_PUBLIC_ENTERPRISE_VERSION != "true"){
+ return
+ }
const active = isItemActive(pathname, item.path);
return (
diff --git a/frontend/src/pages/_app.js b/frontend/src/pages/_app.js
index 7bc21fb..3c4bdc9 100644
--- a/frontend/src/pages/_app.js
+++ b/frontend/src/pages/_app.js
@@ -10,6 +10,7 @@ import { createTheme } from 'src/theme';
import { createEmotionCache } from 'src/utils/create-emotion-cache';
import 'simplebar-react/dist/simplebar.min.css';
import { WsProvider } from 'src/contexts/socketio-context';
+import '../utils/map.css';
const clientSideEmotionCache = createEmotionCache();
diff --git a/frontend/src/pages/map.js b/frontend/src/pages/map.js
index 24a111c..18fd812 100644
--- a/frontend/src/pages/map.js
+++ b/frontend/src/pages/map.js
@@ -1,39 +1,120 @@
import Head from 'next/head';
-import { GoogleMap, useLoadScript } from "@react-google-maps/api"
+import { GoogleMap, useLoadScript, Marker, OverlayView } from "@react-google-maps/api"
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
import { useEffect, useMemo, useState } from 'react';
import mapStyles from '../utils/mapStyles.json';
+const getPixelPositionOffset = pixelOffset => (width, height) => ({
+ x: -(width / 2) + pixelOffset.x,
+ y: -(height / 2) + pixelOffset.y
+});
+
+const Popup = props => {
+ return (
+
+
+
+ );
+};
+
const Page = () => {
const libraries = useMemo(() => ['places'], []);
const [mapCenter, setMapCenter] = useState(null);
+ const [markers, setMarkers] = useState([]);
+ const [activeMarker, setActiveMarker] = useState(null);
+ const [activeMarkerdata, setActiveMarkerdata] = useState(null);
+
+ const fetchMarkers = async () => {
+
+ var myHeaders = new Headers();
+ myHeaders.append("Content-Type", "application/json");
+ myHeaders.append("Authorization", localStorage.getItem("token"));
+
+ var requestOptions = {
+ method: 'GET',
+ headers: myHeaders,
+ redirect: 'follow'
+ };
+
+ let result = await fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/map`, requestOptions)
+
+ if (result.status == 200) {
+ const content = await result.json()
+ setMarkers(content)
+ }else if (result.status == 403) {
+ console.log("num tenx permissão, seu boca de sandália")
+ return router.push("/403")
+ }else if (result.status == 401){
+ console.log("taix nem autenticado, sai fora oh")
+ return router.push("/auth/login")
+ } else {
+ console.log("agora quebrasse ux córno mô quiridu")
+ const content = await result.json()
+ throw new Error(content);
+ }
+ }
+
+ const fetchActiveMarkerData = async (id) => {
+ var myHeaders = new Headers();
+ myHeaders.append("Content-Type", "application/json");
+ myHeaders.append("Authorization", localStorage.getItem("token"));
+
+ var requestOptions = {
+ method: 'GET',
+ headers: myHeaders,
+ redirect: 'follow'
+ };
+
+ let result = await fetch(`${process.env.NEXT_PUBLIC_REST_ENDPOINT || ""}/api/device?id=`+id, requestOptions)
+
+ if (result.status == 200) {
+ const content = await result.json()
+ setActiveMarkerdata(content)
+ }else if (result.status == 403) {
+ return router.push("/403")
+ }else if (result.status == 401){
+ return router.push("/auth/login")
+ } else {
+ console.log("no device info found")
+ const content = await result.json()
+ }
+ }
useEffect(()=> {
- // Check if geolocation is supported by the browser
- if ("geolocation" in navigator) {
- // Prompt user for permission to access their location
- navigator.geolocation.getCurrentPosition(
- // Get the user's latitude and longitude coordinates
- // Success callback function
- function(position) {
- // Update the map with the user's new location
- setMapCenter({
- lat: position.coords.latitude,
- lng: position.coords.longitude,
- })
- },
- // Error callback function
- function(error) {
- // Handle errors, e.g. user denied location sharing permissions
- console.error("Error getting user location:", error);
- }
- );
- } else {
- // Geolocation is not supported by the browser
- console.error("Geolocation is not supported by this browser.");
- }
+ fetchMarkers();
+ // Check if geolocation is supported by the browser
+ if ("geolocation" in navigator) {
+ // Prompt user for permission to access their location
+ navigator.geolocation.getCurrentPosition(
+ // Get the user's latitude and longitude coordinates
+ // Success callback function
+ function(position) {
+ // Update the map with the user's new location
+ setMapCenter({
+ lat: position.coords.latitude,
+ lng: position.coords.longitude,
+ })
+ },
+ // Error callback function
+ function(error) {
+ // Handle errors, e.g. user denied location sharing permissions
+ console.error("Error getting user location:", error);
+ }
+ );
+ } else {
+ // Geolocation is not supported by the browser
+ console.error("Geolocation is not supported by this browser.");
+ }
},[])
const mapOptions = useMemo(
@@ -59,7 +140,7 @@ const Page = () => {
return
Loading...
;
}
- return ( mapCenter &&
+ return ( mapCenter && markers &&
<>
@@ -73,7 +154,51 @@ const Page = () => {
mapContainerStyle={{ width: '100%', height: '100%' }}
onLoad={() => console.log('Map Component Loaded...')}
clickableIcons={false}
- />
+ >
+ {
+ markers.map((marker, index) => (
+ {
+ setActiveMarkerdata(null);
+ if (activeMarker?.sn === marker.sn) {
+ setActiveMarker(null);
+ return;
+ }
+ fetchActiveMarkerData(marker.sn);
+ setActiveMarker({
+ sn: marker.sn,
+ position: { lat: marker.coordinates.lat, lng: marker.coordinates.lng }
+ });
+ }}
+ >
+
+ ))
+ }
+ {activeMarker &&
+
+ SN: {activeMarker.sn}
+
+
Model: {activeMarkerdata.Model?activeMarkerdata.Model:activeMarkerdata.ProductClass}
+
Alias: {activeMarkerdata.Alias}
+
Status: {activeMarkerdata.Status == 2 ? online : offline}
+
+
+ : no device info found
}
+ />}
+
>
)};
diff --git a/frontend/src/utils/map.css b/frontend/src/utils/map.css
new file mode 100644
index 0000000..55a1725
--- /dev/null
+++ b/frontend/src/utils/map.css
@@ -0,0 +1,47 @@
+/* The location pointed to by the popup tip. */
+.popup-tip-anchor {
+ height: 0;
+ position: absolute;
+ /* The max width of the info window. */
+ width: 200px;
+ }
+ /* The bubble is anchored above the tip. */
+ .popup-bubble-anchor {
+ position: absolute;
+ width: 100%;
+ bottom: /* TIP_HEIGHT= */ 8px;
+ left: 0;
+ }
+ /* Draw the tip. */
+ .popup-bubble-anchor::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ /* Center the tip horizontally. */
+ transform: translate(-50%, 0);
+ /* The tip is a https://css-tricks.com/snippets/css/css-triangle/ */
+ width: 0;
+ height: 0;
+ /* The tip is 8px high, and 12px wide. */
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-top: /* TIP_HEIGHT= */ 8px solid white;
+ }
+ /* The popup bubble itself. */
+ .popup-bubble-content {
+ position: absolute;
+ top: 0;
+ left: 0;
+ transform: translate(-50%, -100%);
+ /* Style the info window. */
+ background-color: white;
+ padding: 5px;
+ border-radius: 5px;
+ font-family: sans-serif;
+ font-size: 14px ;
+ overflow-y: auto;
+ max-height: 80px;
+ box-shadow: 0px 2px 10px 1px rgba(0, 0, 0, 0.5);
+ }
+
\ No newline at end of file