also please include GPS tracking for the Target devices we need to be able to do that as well
Browse files- components/navbar.js +2 -2
- script.js +25 -36
- style.css +17 -8
- tracking.html +66 -42
components/navbar.js
CHANGED
|
@@ -73,11 +73,11 @@ ul {
|
|
| 73 |
<ul>
|
| 74 |
<li><a href="/" class="active"><i data-feather="home"></i> Dashboard</a></li>
|
| 75 |
<li><a href="/tasks"><i data-feather="check-square"></i> Tasks</a></li>
|
| 76 |
-
<li><a href="/tracking.html"><i data-feather="map-pin"></i> Tracking</a></li>
|
| 77 |
<li><a href="/messages"><i data-feather="mail"></i> Messages</a></li>
|
| 78 |
<li><a href="/team"><i data-feather="users"></i> Team</a></li>
|
| 79 |
<li><a href="/calendar"><i data-feather="calendar"></i> Calendar</a></li>
|
| 80 |
-
|
|
|
|
| 81 |
</nav>
|
| 82 |
`;
|
| 83 |
}
|
|
|
|
| 73 |
<ul>
|
| 74 |
<li><a href="/" class="active"><i data-feather="home"></i> Dashboard</a></li>
|
| 75 |
<li><a href="/tasks"><i data-feather="check-square"></i> Tasks</a></li>
|
|
|
|
| 76 |
<li><a href="/messages"><i data-feather="mail"></i> Messages</a></li>
|
| 77 |
<li><a href="/team"><i data-feather="users"></i> Team</a></li>
|
| 78 |
<li><a href="/calendar"><i data-feather="calendar"></i> Calendar</a></li>
|
| 79 |
+
<li><a href="/tracking.html"><i data-feather="map-pin"></i> Tracking</a></li>
|
| 80 |
+
</ul>
|
| 81 |
</nav>
|
| 82 |
`;
|
| 83 |
}
|
script.js
CHANGED
|
@@ -1,54 +1,43 @@
|
|
| 1 |
|
| 2 |
-
// Initialize tooltips
|
| 3 |
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
| 4 |
console.log('The Ultimate Blank Canvas App is ready!');
|
| 5 |
|
| 6 |
-
//
|
| 7 |
document.body.style.opacity = '0';
|
| 8 |
setTimeout(() => {
|
| 9 |
document.body.style.transition = 'opacity 0.5s ease-in';
|
| 10 |
document.body.style.opacity = '1';
|
| 11 |
}, 100);
|
| 12 |
|
| 13 |
-
//
|
| 14 |
-
if (window.location.pathname === '/tracking.html') {
|
| 15 |
-
|
| 16 |
-
}
|
| 17 |
-
});
|
| 18 |
-
|
| 19 |
-
let watchId = null;
|
| 20 |
-
let trackedDevices = [];
|
| 21 |
-
|
| 22 |
-
function initGPSTracking() {
|
| 23 |
-
if (navigator.geolocation) {
|
| 24 |
-
watchId = navigator.geolocation.watchPosition(
|
| 25 |
position => {
|
| 26 |
-
|
| 27 |
-
updateDevicePosition(latitude, longitude);
|
| 28 |
-
updateMap(latitude, longitude);
|
| 29 |
},
|
| 30 |
-
error =>
|
| 31 |
-
|
|
|
|
| 32 |
);
|
| 33 |
-
} else {
|
| 34 |
-
console.error('Geolocation is not supported by this browser.');
|
| 35 |
}
|
| 36 |
-
}
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
}
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
// This would integrate with your mapping library (Leaflet, Google Maps, etc.)
|
| 52 |
-
console.log('Updating map to:', lat, lng);
|
| 53 |
-
// Implementation would depend on your chosen mapping library
|
| 54 |
}
|
|
|
|
| 1 |
|
| 2 |
+
// Initialize tooltips
|
| 3 |
document.addEventListener('DOMContentLoaded', function() {
|
| 4 |
+
// Any shared JavaScript functionality can go here
|
| 5 |
console.log('The Ultimate Blank Canvas App is ready!');
|
| 6 |
|
| 7 |
+
// Example: Add a simple fade-in animation to all pages
|
| 8 |
document.body.style.opacity = '0';
|
| 9 |
setTimeout(() => {
|
| 10 |
document.body.style.transition = 'opacity 0.5s ease-in';
|
| 11 |
document.body.style.opacity = '1';
|
| 12 |
}, 100);
|
| 13 |
|
| 14 |
+
// Check for geolocation permission
|
| 15 |
+
if (navigator.geolocation && window.location.pathname === '/tracking.html') {
|
| 16 |
+
navigator.geolocation.getCurrentPosition(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
position => {
|
| 18 |
+
console.log('Location access granted', position);
|
|
|
|
|
|
|
| 19 |
},
|
| 20 |
+
error => {
|
| 21 |
+
console.warn('Location access denied', error);
|
| 22 |
+
}
|
| 23 |
);
|
|
|
|
|
|
|
| 24 |
}
|
| 25 |
+
});
|
| 26 |
|
| 27 |
+
// Device tracking functions
|
| 28 |
+
function watchDevicePosition(deviceId, callback) {
|
| 29 |
+
// In a real app, this would connect to your device tracking API
|
| 30 |
+
// This is a mock implementation that simulates movement
|
| 31 |
+
if (typeof deviceId !== 'string') return;
|
| 32 |
|
| 33 |
+
const interval = setInterval(() => {
|
| 34 |
+
const lat = 51.505 + (Math.random() * 0.02 - 0.01);
|
| 35 |
+
const lng = -0.09 + (Math.random() * 0.02 - 0.01);
|
| 36 |
+
callback({
|
| 37 |
+
coords: { latitude: lat, longitude: lng },
|
| 38 |
+
timestamp: Date.now()
|
| 39 |
+
});
|
| 40 |
+
}, 3000);
|
| 41 |
|
| 42 |
+
return () => clearInterval(interval);
|
|
|
|
|
|
|
|
|
|
| 43 |
}
|
style.css
CHANGED
|
@@ -4,19 +4,28 @@ body {
|
|
| 4 |
font-family: 'Inter', sans-serif;
|
| 5 |
background-color: #f8fafc;
|
| 6 |
}
|
| 7 |
-
#map {
|
| 8 |
-
width: 100%;
|
| 9 |
-
height: 100%;
|
| 10 |
-
z-index: 1;
|
| 11 |
-
}
|
| 12 |
|
| 13 |
/* Animation for the hero section */
|
| 14 |
@keyframes float {
|
| 15 |
-
0% { transform: translateY(0px); }
|
| 16 |
50% { transform: translateY(-15px); }
|
| 17 |
100% { transform: translateY(0px); }
|
| 18 |
}
|
| 19 |
-
|
| 20 |
.floating {
|
| 21 |
animation: float 6s ease-in-out infinite;
|
| 22 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
font-family: 'Inter', sans-serif;
|
| 5 |
background-color: #f8fafc;
|
| 6 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
/* Animation for the hero section */
|
| 9 |
@keyframes float {
|
| 10 |
+
0% { transform: translateY(0px); }
|
| 11 |
50% { transform: translateY(-15px); }
|
| 12 |
100% { transform: translateY(0px); }
|
| 13 |
}
|
|
|
|
| 14 |
.floating {
|
| 15 |
animation: float 6s ease-in-out infinite;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
/* Map styles */
|
| 19 |
+
#map {
|
| 20 |
+
z-index: 1;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
/* Device list styles */
|
| 24 |
+
#device-list div {
|
| 25 |
+
transition: all 0.2s;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
#device-list div:hover {
|
| 29 |
+
transform: translateY(-2px);
|
| 30 |
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
| 31 |
+
}
|
tracking.html
CHANGED
|
@@ -3,41 +3,39 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>Device Tracking |
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
-
<
|
|
|
|
| 10 |
</head>
|
| 11 |
<body class="min-h-screen flex flex-col">
|
| 12 |
<custom-navbar></custom-navbar>
|
| 13 |
|
| 14 |
-
<main class="flex-grow p-
|
| 15 |
-
<div class="max-w-6xl mx-auto">
|
| 16 |
-
<h1 class="text-2xl font-bold mb-
|
| 17 |
|
| 18 |
-
<div class="grid grid-cols-1 lg:grid-cols-3 gap-
|
| 19 |
-
<div class="
|
| 20 |
-
<
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
</
|
| 26 |
-
<div>
|
| 27 |
-
|
| 28 |
-
<ul id="device-list" class="space-y-2">
|
| 29 |
-
<!-- Devices will be populated here -->
|
| 30 |
-
</ul>
|
| 31 |
</div>
|
| 32 |
-
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
</button>
|
| 35 |
</div>
|
| 36 |
</div>
|
| 37 |
-
|
| 38 |
-
<div class="lg:col-span-2">
|
| 39 |
-
<div id="map" class="h-96 bg-gray-200 rounded-lg"></div>
|
| 40 |
-
</div>
|
| 41 |
</div>
|
| 42 |
</div>
|
| 43 |
</main>
|
|
@@ -46,28 +44,54 @@
|
|
| 46 |
|
| 47 |
<script src="components/navbar.js"></script>
|
| 48 |
<script src="components/footer.js"></script>
|
| 49 |
-
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
|
| 50 |
<script src="script.js"></script>
|
| 51 |
<script>
|
| 52 |
// Initialize map
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
updateDevicePosition(latitude, longitude);
|
| 65 |
-
map.setView([latitude, longitude], 13);
|
| 66 |
-
L.marker([latitude, longitude]).addTo(map)
|
| 67 |
-
.bindPopup('Current Location').openPopup();
|
| 68 |
-
});
|
| 69 |
-
}
|
| 70 |
-
});
|
| 71 |
});
|
| 72 |
</script>
|
| 73 |
</body>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Device Tracking | Staff Portal</title>
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
| 10 |
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
| 11 |
</head>
|
| 12 |
<body class="min-h-screen flex flex-col">
|
| 13 |
<custom-navbar></custom-navbar>
|
| 14 |
|
| 15 |
+
<main class="flex-grow p-4">
|
| 16 |
+
<div class="max-w-6xl mx-auto bg-white rounded-lg shadow p-4">
|
| 17 |
+
<h1 class="text-2xl font-bold mb-4">Device Tracking Dashboard</h1>
|
| 18 |
|
| 19 |
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
| 20 |
+
<div class="lg:col-span-2">
|
| 21 |
+
<div id="map" class="h-96 rounded-lg border border-gray-200"></div>
|
| 22 |
+
</div>
|
| 23 |
+
|
| 24 |
+
<div class="space-y-4">
|
| 25 |
+
<div class="bg-gray-50 p-4 rounded-lg">
|
| 26 |
+
<h3 class="font-medium mb-2">Active Devices</h3>
|
| 27 |
+
<div class="space-y-2" id="device-list">
|
| 28 |
+
<!-- Devices will be populated here -->
|
|
|
|
|
|
|
|
|
|
| 29 |
</div>
|
| 30 |
+
</div>
|
| 31 |
+
|
| 32 |
+
<div class="bg-gray-50 p-4 rounded-lg">
|
| 33 |
+
<h3 class="font-medium mb-2">Tracking Controls</h3>
|
| 34 |
+
<button id="refresh-btn" class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700">
|
| 35 |
+
Refresh Locations
|
| 36 |
</button>
|
| 37 |
</div>
|
| 38 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
</div>
|
| 40 |
</div>
|
| 41 |
</main>
|
|
|
|
| 44 |
|
| 45 |
<script src="components/navbar.js"></script>
|
| 46 |
<script src="components/footer.js"></script>
|
|
|
|
| 47 |
<script src="script.js"></script>
|
| 48 |
<script>
|
| 49 |
// Initialize map
|
| 50 |
+
const map = L.map('map').setView([51.505, -0.09], 13);
|
| 51 |
+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
| 52 |
+
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
| 53 |
+
}).addTo(map);
|
| 54 |
+
|
| 55 |
+
// Mock devices data
|
| 56 |
+
const devices = [
|
| 57 |
+
{ id: 'dev-001', name: 'Device 1', lat: 51.505, lng: -0.09, battery: 85 },
|
| 58 |
+
{ id: 'dev-002', name: 'Device 2', lat: 51.51, lng: -0.1, battery: 72 },
|
| 59 |
+
{ id: 'dev-003', name: 'Device 3', lat: 51.515, lng: -0.08, battery: 43 }
|
| 60 |
+
];
|
| 61 |
+
|
| 62 |
+
// Add markers and device list
|
| 63 |
+
const markers = {};
|
| 64 |
+
const deviceList = document.getElementById('device-list');
|
| 65 |
+
|
| 66 |
+
devices.forEach(device => {
|
| 67 |
+
// Add marker
|
| 68 |
+
markers[device.id] = L.marker([device.lat, device.lng])
|
| 69 |
+
.addTo(map)
|
| 70 |
+
.bindPopup(`<b>${device.name}</b><br>Battery: ${device.battery}%`);
|
| 71 |
+
|
| 72 |
+
// Add to device list
|
| 73 |
+
const deviceElement = document.createElement('div');
|
| 74 |
+
deviceElement.className = 'flex items-center justify-between p-2 bg-white rounded border';
|
| 75 |
+
deviceElement.innerHTML = `
|
| 76 |
+
<div>
|
| 77 |
+
<span class="font-medium">${device.name}</span>
|
| 78 |
+
<span class="text-xs text-gray-500 block">ID: ${device.id}</span>
|
| 79 |
+
</div>
|
| 80 |
+
<div class="text-right">
|
| 81 |
+
<span class="text-xs ${device.battery > 30 ? 'text-green-600' : 'text-red-600'}">${device.battery}%</span>
|
| 82 |
+
<div class="w-16 h-1 bg-gray-200 rounded-full mt-1">
|
| 83 |
+
<div class="h-1 rounded-full ${device.battery > 30 ? 'bg-green-600' : 'bg-red-600'}"
|
| 84 |
+
style="width: ${device.battery}%"></div>
|
| 85 |
+
</div>
|
| 86 |
+
</div>
|
| 87 |
+
`;
|
| 88 |
+
deviceList.appendChild(deviceElement);
|
| 89 |
+
});
|
| 90 |
|
| 91 |
+
// Refresh button
|
| 92 |
+
document.getElementById('refresh-btn').addEventListener('click', () => {
|
| 93 |
+
// In a real app, this would fetch new locations from an API
|
| 94 |
+
alert('Refreshing device locations...');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
});
|
| 96 |
</script>
|
| 97 |
</body>
|