Skip to content

Commit

Permalink
Add vehicle tracking dashboard with journey history and alerts panel
Browse files Browse the repository at this point in the history
  • Loading branch information
hardikprakash committed Nov 7, 2024
1 parent 5dd7b2e commit ae9bdbb
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 28 deletions.
31 changes: 26 additions & 5 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
// src/App.js
import React from 'react';
import InventoryDashboard from './components/InventoryDashboard';
import VehicleMap from './components/VehicleMap';
import JourneyHistory from './components/JourneyHistory';
import AlertsPanel from './components/AlertsPanel';

function App() {
return (
<div className="App">
<InventoryDashboard />
<h1>Vehicle Tracking</h1>
<VehicleMap vehicleId="vehicle_1" />
<div className="min-h-screen bg-gray-100 flex flex-col items-center p-6">
<header className="mb-8 text-center">
<h1 className="text-3xl font-bold text-gray-800 mb-4">SupplySync Dashboard</h1>
<p className="text-gray-600">Manage inventory, track vehicles, and view journey history and alerts.</p>
</header>

<main className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3 w-full max-w-7xl">
<section className="col-span-1 md:col-span-2 lg:col-span-1">
<InventoryDashboard />
</section>

<section className="col-span-1">
<h2 className="text-2xl font-semibold text-gray-700 mb-4">Vehicle Tracking</h2>
<VehicleMap vehicleId="vehicle_1" />
</section>

<section className="col-span-1 md:col-span-2">
<JourneyHistory vehicleId="vehicle_1" />
</section>

<section className="col-span-1">
<AlertsPanel />
</section>
</main>
</div>
);
}
Expand Down
38 changes: 38 additions & 0 deletions src/components/AlertsPanel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useEffect, useState } from "react";
import { fetchAlerts } from "../services/api";

const AlertsPanel = () => {
const [alerts, setAlerts] = useState([]);

useEffect(() => {
const interval = setInterval(async () => {
try {
const data = await fetchAlerts();
setAlerts(data);
} catch (error) {
console.error("Error fetching alerts:", error);
}
}, 10000);

return () => clearInterval(interval);
}, []);

return (
<div className="alerts-panel bg-red-100 p-4 rounded-lg shadow-md max-w-md mx-auto">
<h2 className="text-xl font-bold text-red-600 mb-4">Active Alerts</h2>
<ul className="space-y-2">
{alerts.map((alert) => (
<li
key={alert.id}
className="p-3 bg-white rounded-lg shadow-sm border-l-4 border-red-600"
>
<strong className="font-semibold text-red-600">{alert.alert_type}:</strong>{" "}
<span className="text-gray-700">{alert.description}</span>
</li>
))}
</ul>
</div>
);
};

export default AlertsPanel;
30 changes: 22 additions & 8 deletions src/components/InventoryDashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ function InventoryDashboard() {
const [inventory, setInventory] = useState([]);

useEffect(() => {
// Fetch inventory data on component mount
fetch('http://localhost:8000/api/inventory')
.then(response => response.json())
.then(data => setInventory(data))
Expand All @@ -28,14 +27,29 @@ function InventoryDashboard() {
};

return (
<div>
<h2>Inventory Dashboard</h2>
<ul>
<div className="inventory-dashboard bg-gray-100 p-6 rounded-lg shadow-md max-w-2xl mx-auto">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Inventory Dashboard</h2>
<ul className="space-y-4">
{inventory.map(item => (
<li key={item.id}>
{item.item_name} - Stock: {item.stock_level}
<button onClick={() => updateStock(item.id, 1)}>Add Stock</button>
<button onClick={() => updateStock(item.id, -1)}>Remove Stock</button>
<li key={item.id} className="p-4 bg-white rounded-lg shadow-sm flex items-center justify-between">
<div>
<span className="font-semibold text-gray-700">{item.item_name}</span> -
<span className="ml-2 text-gray-600">Stock: {item.stock_level}</span>
</div>
<div className="space-x-2">
<button
onClick={() => updateStock(item.id, 1)}
className="px-3 py-1 bg-green-500 text-white rounded-lg hover:bg-green-600 transition"
>
Add Stock
</button>
<button
onClick={() => updateStock(item.id, -1)}
className="px-3 py-1 bg-red-500 text-white rounded-lg hover:bg-red-600 transition"
>
Remove Stock
</button>
</div>
</li>
))}
</ul>
Expand Down
74 changes: 74 additions & 0 deletions src/components/JourneyHistory.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useEffect, useState } from "react";
import {
MapContainer,
TileLayer,
Marker,
Popup,
Polyline,
} from "react-leaflet";
import "leaflet/dist/leaflet.css";

function JourneyHistory({ vehicleId }) {
const [history, setHistory] = useState([]);

useEffect(() => {
fetch(`http://localhost:8000/gps/history?vehicle_id=${vehicleId}`)
.then((response) => response.json())
.then((data) => setHistory(data.journey_history))
.catch((error) =>
console.error("Error fetching journey history:", error)
);
}, [vehicleId]);

if (!history.length)
return (
<p className="text-center text-gray-500 py-4">
Loading journey history...
</p>
);

const routeCoordinates = history.map((point) => [
point.latitude,
point.longitude,
]);

return (
<div className="journey-history-container bg-gray-100 p-6 rounded-lg shadow-md max-w-4xl mx-auto">
<h2 className="text-2xl font-bold text-gray-800 mb-4 text-center">
Journey History
</h2>
<MapContainer
center={routeCoordinates[0]}
zoom={13}
style={{ height: "400px", width: "100%" }}
className="rounded-lg shadow-sm"
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
<Polyline positions={routeCoordinates} color="blue" />
{history.map((point, index) => (
<Marker
key={index}
position={[point.latitude, point.longitude]}
>
<Popup>
<div className="text-center">
<span className="font-semibold">
Checkpoint {index + 1}
</span>
<br />
<span className="text-gray-600">
{new Date(point.timestamp).toLocaleString()}
</span>
</div>
</Popup>
</Marker>
))}
</MapContainer>
</div>
);
}

export default JourneyHistory;
12 changes: 9 additions & 3 deletions src/components/ScanSimulator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ function ScanSimulator({ itemId }) {
};

return (
<div>
<button onClick={simulateScan}>Simulate Scan</button>
{message && <p>{message}</p>}
<div className="bg-white p-4 rounded-lg shadow-md max-w-sm mx-auto text-center">
<h2 className="text-xl font-bold text-gray-700 mb-4">Scan Simulator</h2>
<button
onClick={simulateScan}
className="bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg mb-4"
>
Simulate Scan
</button>
{message && <p className="text-green-600 font-medium">{message}</p>}
</div>
);
}
Expand Down
31 changes: 19 additions & 12 deletions src/components/VehicleMap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,27 @@ function VehicleMap({ vehicleId }) {
return () => clearInterval(intervalId);
}, [vehicleId]);

if (!location) return <p>Loading vehicle location...</p>;
if (!location) return <p className="text-center text-gray-600">Loading vehicle location...</p>;

return (
<MapContainer center={[location.lat, location.lon]} zoom={13} style={{ height: "400px", width: "100%" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
<Marker position={[location.lat, location.lon]}>
<Popup>
Vehicle {vehicleId} is here.
</Popup>
</Marker>
</MapContainer>
<div className="bg-white rounded-lg shadow-md p-4 max-w-2xl mx-auto mt-4">
<h2 className="text-2xl font-bold text-gray-700 mb-4 text-center">Vehicle Map</h2>
<MapContainer
center={[location.lat, location.lon]}
zoom={13}
className="h-96 w-full rounded-lg overflow-hidden"
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
<Marker position={[location.lat, location.lon]}>
<Popup>
Vehicle {vehicleId} is here.
</Popup>
</Marker>
</MapContainer>
</div>
);
}

Expand Down
23 changes: 23 additions & 0 deletions src/services/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import axios from "axios";

const API_BASE_URL = "http://localhost:8000";

export const updateGPSLocation = async (vehicleId) => {
try {
const response = await axios.post(`${API_BASE_URL}/gps/update`, { vehicle_id: vehicleId });
return response.data;
} catch (error) {
console.error("Error updating GPS location:", error);
throw error;
}
};

export const fetchAlerts = async () => {
try {
const response = await axios.get(`${API_BASE_URL}/alerts`);
return response.data;
} catch (error) {
console.error("Error fetching alerts:", error);
throw error;
}
};

0 comments on commit ae9bdbb

Please sign in to comment.