diff --git a/package.json b/package.json
index de83eaf..efcdb3a 100644
--- a/package.json
+++ b/package.json
@@ -19,8 +19,10 @@
"cmdk": "^1.1.1",
"dagre": "^0.8.5",
"framer-motion": "^12.40.0",
+ "leaflet": "^1.9.4",
"react": "^19.2.6",
"react-dom": "^19.2.6",
+ "react-leaflet": "^4.2.1",
"reactflow": "^11.11.4",
"zustand": "^5.0.14"
},
@@ -28,6 +30,7 @@
"@eslint/js": "^10.0.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
+ "@types/leaflet": "^1.9.21",
"@types/node": "^24.12.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a13fe91..b415050 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -20,12 +20,18 @@ importers:
framer-motion:
specifier: ^12.40.0
version: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
+ leaflet:
+ specifier: ^1.9.4
+ version: 1.9.4
react:
specifier: ^19.2.6
version: 19.2.7
react-dom:
specifier: ^19.2.6
version: 19.2.7(react@19.2.7)
+ react-leaflet:
+ specifier: ^4.2.1
+ version: 4.2.1(leaflet@1.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
reactflow:
specifier: ^11.11.4
version: 11.11.4(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -42,6 +48,9 @@ importers:
'@testing-library/react':
specifier: ^16.3.2
version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
+ '@types/leaflet':
+ specifier: ^1.9.21
+ version: 1.9.21
'@types/node':
specifier: ^24.12.3
version: 24.13.2
@@ -492,6 +501,13 @@ packages:
'@types/react':
optional: true
+ '@react-leaflet/core@2.1.0':
+ resolution: {integrity: sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==}
+ peerDependencies:
+ leaflet: ^1.9.0
+ react: ^18.0.0
+ react-dom: ^18.0.0
+
'@reactflow/background@11.3.14':
resolution: {integrity: sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==}
peerDependencies:
@@ -772,6 +788,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ '@types/leaflet@1.9.21':
+ resolution: {integrity: sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==}
+
'@types/node@24.13.2':
resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==}
@@ -1297,6 +1316,9 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ leaflet@1.9.4:
+ resolution: {integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==}
+
levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
@@ -1499,6 +1521,13 @@ packages:
react-is@17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+ react-leaflet@4.2.1:
+ resolution: {integrity: sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==}
+ peerDependencies:
+ leaflet: ^1.9.0
+ react: ^18.0.0
+ react-dom: ^18.0.0
+
react-remove-scroll-bar@2.3.8:
resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
engines: {node: '>=10'}
@@ -2270,6 +2299,12 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.17
+ '@react-leaflet/core@2.1.0(leaflet@1.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
+ dependencies:
+ leaflet: 1.9.4
+ react: 19.2.7
+ react-dom: 19.2.7(react@19.2.7)
+
'@reactflow/background@11.3.14(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
dependencies:
'@reactflow/core': 11.11.4(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -2572,6 +2607,10 @@ snapshots:
'@types/json-schema@7.0.15': {}
+ '@types/leaflet@1.9.21':
+ dependencies:
+ '@types/geojson': 7946.0.16
+
'@types/node@24.13.2':
dependencies:
undici-types: 7.18.2
@@ -3118,6 +3157,8 @@ snapshots:
dependencies:
json-buffer: 3.0.1
+ leaflet@1.9.4: {}
+
levn@0.4.1:
dependencies:
prelude-ls: 1.2.1
@@ -3276,6 +3317,13 @@ snapshots:
react-is@17.0.2: {}
+ react-leaflet@4.2.1(leaflet@1.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
+ dependencies:
+ '@react-leaflet/core': 2.1.0(leaflet@1.9.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
+ leaflet: 1.9.4
+ react: 19.2.7
+ react-dom: 19.2.7(react@19.2.7)
+
react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7):
dependencies:
react: 19.2.7
diff --git a/src/App.tsx b/src/App.tsx
index af47172..342a37e 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,6 +11,7 @@ import SsoCallback from "./scenes/SsoCallback";
import Chat from "./scenes/Chat";
import Agent from "./scenes/Agent";
import Hub from "./scenes/Hub";
+import GeoAttendance from "./scenes/GeoAttendance";
import CommandBar from "./components/CommandBar";
import Toaster from "./components/Toaster";
import Console from "./components/Console";
@@ -163,6 +164,7 @@ export default function App() {
{scene === "hub-procurement" &&
+ Live attendance for stores, offices, and warehouses. Click a marker to see who's checked in and when. Powered by OpenStreetMap tiles — no proprietary mapping key required. +
+