fix: correct 3D facility view navigation path (/facility-3d → /facility/3d)
Some checks are pending
Deploy to Production / deploy (push) Waiting to run
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run

This commit is contained in:
fullsizemalt 2025-12-18 11:43:25 -08:00
parent 4d900d7bec
commit 8916acbe4b
8 changed files with 518 additions and 384 deletions

View file

@ -0,0 +1,89 @@
# 3D Facility Viewer Refactor Plan: "Project Panopticon"
## 1. Executive Summary
**Objective:** Transform the 3D Facility Viewer from a basic visualization tool into a comprehensive, "dead simple" interface for managing complex facility operations.
**Core Philosophy:** "Functional Realism". The interface should look premium and architectural, but every visual element must serve a data-driven purpose.
**Key Goals:**
1. **Human Readability:** Instant understanding of facility layout, plant locations, and environmental status.
2. **Temporal Visualization:** Ability to visualize data *over time* (e.g., "Show me the spread of this batch over the last 30 days").
3. **Rapid Location:** Locate any METRC-compliant plant or batch instantly with clear visual guidance.
## 2. Visual & UX Overhaul
### A. "Clean Industrial" Aesthetics
* **Move away from:** Wireframes, glowing neon lines, dark "hacker" themes.
* **Move toward:** Clean concrete textures, matte metal finishes, soft global illumination, and distinct color coding for biological vs. structural elements.
* **Lighting:** Use an HDRI environment (`preset="city"` or similar) for realistic reflections, plus soft ambient occlusion (`<ContactShadows />`) to ground objects.
### B. "Human Readable" Indicators
* **Smart Labels:** Instead of static 3D text floating in space, use `Html` overlays that scale and fade based on camera distance (LOD).
* *Close Zoom:* Show individual Plant Tags and Health Stats.
* *Medium Zoom:* Show Rack/Shelf IDs and Aggregate Health.
* *Far Zoom:* Show Room Names and Environmental Averages.
* **Beacons:** When searching for a plant, do not just snap the camera. Place a vertical "light beacon" or animated indicator over the target so the user sees *where* it is in context before zooming in.
### C. Controls & Navigation
* **Hybrid Controls:**
* **WASD + Right Click Drag:** For "gamer" style free-flight.
* **Click-to-Move:** Click any room floor to smoothly fly the camera there.
* **Double-Click:** Focus specifically on a rack or plant.
* **Tour Mode:** A "Next Issue" button to cycle the camera through all plants with "Critical" health or environmental alerts.
## 3. New Feature: "The Time Slider"
* **Concept:** A timeline interface at the bottom of the screen.
* **Function:** Dragging the slider behaves like a video scrubber.
* *Past:* Visualize historical plant positions (from `PlantLocationHistory`). See where a batch started and how it moved.
* *Present:* Live state.
* *Future (Projected):* Visualize yield forecasts or space planning (from `Yield` model).
## 4. Technical Architecture Refactor
### A. Component Decomposition
The current `Facility3DViewerPage.tsx` is becoming monolithic. We will break it down:
* `FacilityScene.tsx`: Main canvas and lighting setup.
* `FacilityWorld.tsx`: Handles the "physics" and separate rooms.
* `RoomObject.tsx`: Encapsulates a single room's logic (floor, walls, labels).
* `SmartRack.tsx`: Manages a single rack/section, including its tiers and labels.
* `PlantSystem.tsx`: Optimized `InstancedMesh` system for rendering thousands of plants efficiently.
### B. Data & State Management
* **Zustand Store:** Move 3D state (selected plant, camera target, visualization mode, timeline position) out of React `useState` and into a global store for better performance and access outside the canvas.
* **React Query:** Use for fetching standard API data.
* **Optimized History Fetching:** New API endpoint needed: `GET /api/facilities/:id/history-snapshot?date=ISO_DATE` to fetch the state of the facility at a specific point in time.
## 5. Implementation Phases
### Phase 1: The "Visual Foundation" (Current Priority)
* [x] Split code into smaller components.
* [x] Implement "Clean Industrial" materials and lighting. *(Using Environment preset="city", ContactShadows)*
* [x] Fix the camera controller to be "smooth yet precise". *(CameraControls with WASD + mouse)*
* [ ] Add "LOD" (Level of Detail) labels that fade in/out. *(Future enhancement)*
### Phase 2: "Search & Locate" (Locating Plants) ✅ COMPLETE
* [x] Build the "Search Sidebar" with fuzzy search for Tags/Batches. *(PlantSearch.tsx)*
* [x] Implement the "Beacon" visual indicator system. *(Beacon.tsx - animated light beam)*
* [x] Add "Highlight Mode": Dim the entire facility *except* the search results. *(dimMode + highlightedTags)*
### Phase 3: "The Time Machine"
* [ ] Implement the UI Slider component.
* [ ] Create backend endpoint for historical snapshots.
* [ ] Wire up the slider to update plant positions dynamically.
## 6. Review Request
Does this plan align with your vision for "dead simple" and "human readable"? specifically:
1. Is the **Time Slider** a desired feature for "complex data over time"?
2. Do you agree with the **"Clean Industrial"** aesthetic direction?

348
STATUS.md
View file

@ -1,10 +1,10 @@
# CA Grow Ops Manager — Project Status # CA Grow Ops Manager — Project Status
**Current Phase**: Phase 1 - Implementation **Current Phase**: Demo-Ready / Polish
**Status**: 🟢 On Track (Week 1 Foundation Complete) **Status**: 🟢 Feature Complete (Phases 1-13 Done)
**Version**: 0.2.0 **Version**: 0.9.0
**Deployed URL**: <https://777wolfpack.runfoo.run> **Deployed URL**: <https://777wolfpack.runfoo.run>
**Last Updated**: 2025-12-09 **Last Updated**: 2025-12-18
--- ---
@ -14,254 +14,172 @@
--- ---
## Current Status: ✅ READY TO BUILD ## Current Status: ✅ DEMO READY
### Completed Milestones ### Completed Phases
- ✅ **Project Initialization** (2025-12-08) | Phase | Description | Status |
- Constitution defined |-------|-------------|--------|
- Project spec created | **Phase 1** | Core Infrastructure - Auth, Rooms, Batches, Touch Points | ✅ Complete |
- 7 feature specs written | **Phase 2** | Tasks & SOPs - Task management, templates, assignments | ✅ Complete |
- Architecture documented | **Phase 3** | Supplies & Inventory - Stock tracking, usage logs | ✅ Complete |
- Compliance notes documented | **Phase 4** | Timeclock - Clock in/out, hour tracking | ✅ Complete |
| **Phase 5** | IPM & Plant Health - Scouting, treatments, health history | ✅ Complete |
- ✅ **Phase 1 Planning** (2025-12-08) | **Phase 6** | Reporting & Analytics - Dashboards, yield reports | ✅ Complete |
- Implementation plan created | **Phase 7** | Facility Layout Designer & Plant Addressing | ✅ Complete |
- Week 1 tasks defined | **Phase 8** | Visitor Management & Access Control | ✅ Complete |
- Architecture decisions made | **Phase 9** | Messaging & Mass Communication | ✅ Complete |
- Timeline established (6 weeks) | **Phase 10** | Compliance & Audit Trail | ✅ Complete |
| **Phase 11** | Accessibility & i18n | ✅ Complete |
### Next Milestone | **Phase 12** | Hardware Integration (QR Codes) | ✅ Partial (QR done, NFC/E-Ink pending) |
| **Phase 13** | Advanced Features (Environment, Financial, AI) | ✅ Complete |
- ⏭️ **Week 1: Infrastructure Setup** (Starting Soon) | **Phase 14** | Facility Monitoring (Cameras) | ✅ Infrastructure deployed |
- 15 tasks defined | **Phase 15** | 3D Facility Visualization | ✅ Phase 1-2 Complete |
- Estimated: 15.5 hours (2 days for 1 dev, 1 day for 2 devs) | **Polish** | UI/UX - Toasts, offline, PWA, mobile gestures | ✅ Complete |
- Deliverable: Working dev environment with Docker Compose
--- ---
## Phase 1 Progress ## 3D Viewer Status (Phase 15)
**Target**: Foundation (v0.1.0) | Sub-Phase | Description | Status |
**Duration**: 6 weeks |-----------|-------------|--------|
**Status**: Planning Complete, Ready to Implement | Phase 1 | Visual Foundation - Components, Materials, Camera | ✅ Complete |
| Phase 2 | Search & Locate - Fuzzy search, Beacon, Dim mode | ✅ Complete |
### Week-by-Week Breakdown | Phase 3 | Time Slider - Historical visualization | ⬜ Roadmapped |
| Week | Focus | Status | Tasks | Estimated Hours |
|------|-------|--------|-------|-----------------|
| 1 | Infrastructure Setup | 📋 Planned | 15 | 15.5 |
| 2 | Authentication & RBAC | 📋 Planned | TBD | ~20 |
| 3 | Core Data Models | 📋 Planned | TBD | ~25 |
| 4 | Frontend UI (Part 1) | 📋 Planned | TBD | ~30 |
| 5 | Frontend UI (Part 2) | 📋 Planned | TBD | ~30 |
| 6 | Testing & Polish | 📋 Planned | TBD | ~25 |
**Total Estimated**: ~145 hours (4-6 weeks for 1 developer, 2-3 weeks for 2 developers)
--- ---
## Architecture Decisions ## Test Coverage
### Backend (Jest)
- **24 total tests**
- **18 passing** (unit tests + graceful skips)
- **6 require running server** (integration tests)
- TypeScript compiles cleanly
### Frontend (Vitest)
- **11 total tests**
- **11 passing**
- Covers: utilities, QR code generation, accessibility, API clients
---
## Key Features
### Core Operations
- ✅ Room and batch management
- ✅ Task templates and assignments
- ✅ Supply inventory tracking
- ✅ Daily walkthrough system
- ✅ Touch point logging
### Compliance
- ✅ Full audit trail (immutable logs)
- ✅ Document versioning with approval workflow
- ✅ Visitor check-in/check-out with badges
- ✅ METRC-compatible plant addressing
### Visualization
- ✅ 3D facility viewer with room navigation
- ✅ Plant search with animated beacon locator
- ✅ Multiple visualization modes (Health, Temp, Humidity, Yield)
- ✅ Deep linking from METRC dashboard
### Accessibility
- ✅ Screen reader support (ARIA labels)
- ✅ Keyboard navigation
- ✅ High contrast mode
- ✅ Reduced motion preference
- ✅ Font size adjustment (Normal/Large/XL)
- ✅ Multi-language support (English/Spanish)
---
## Architecture
### Backend ### Backend
- ✅ **Framework**: Fastify (chosen over Express for performance) - **Framework**: Fastify
- ✅ **Database**: PostgreSQL 15 - **Database**: PostgreSQL 15 + Prisma ORM
- ✅ **ORM**: Prisma - **Auth**: JWT (access + refresh tokens)
- ✅ **Auth**: JWT (access + refresh tokens) - **Testing**: Jest
- ✅ **Testing**: Jest + Supertest
### Frontend ### Frontend
- ✅ **Framework**: Vite + React (chosen over Next.js for simplicity in v1) - **Framework**: Vite + React 18
- ✅ **Components**: shadcn/ui (Radix + Tailwind) - **UI**: Tailwind CSS + DaisyUI + shadcn/ui
- ✅ **Routing**: React Router - **3D**: React Three Fiber (Three.js)
- ✅ **Testing**: Vitest + React Testing Library - **State**: React Query + Context
- **Testing**: Vitest
### Infrastructure ### Infrastructure
- ✅ **Containerization**: Docker + Docker Compose - **Container**: Docker + Docker Compose
- ✅ **Development**: Hot reload for backend and frontend - **Reverse Proxy**: Traefik
- ✅ **Caching**: Redis (for sessions) - **Deployment**: Forgejo CI/CD → nexus-vector
--- ---
## Feature Specs Status ## Outstanding Items
| Feature | Spec Status | Plan Status | Implementation Status | ### High Priority (Demo Prep)
|---------|-------------|-------------|----------------------|
| Tasks and Scheduling | ✅ Complete | ⏭️ Week 3 | ⬜ Not Started | - [ ] Smoke test deployed application
| Batches and Rooms | ✅ Complete | ⏭️ Week 3 | ⬜ Not Started | - [ ] Verify seed data is populated correctly
| Labor and Hours | ✅ Complete | ⏭️ Week 3 | ⬜ Not Started | - [ ] Test 3D viewer search functionality on production
| Compliance and Docs | ✅ Complete | ⏭️ Week 3 | ⬜ Not Started |
| Inventory and Materials | ✅ Complete | 📋 Phase 2 | ⬜ Not Started | ### Medium Priority (Polish)
| Integrations and Hardware | ✅ Complete | 📋 Phase 2 | ⬜ Not Started |
| Communications and Notifications | ✅ Complete | 📋 Phase 2 | ⬜ Not Started | - [ ] LOD labels (fade by camera distance) in 3D viewer
- [ ] Time slider for historical plant positions
- [ ] Automated a11y testing (axe-core)
### Future Phases
- [ ] NFC badge integration
- [ ] E-Ink display network
- [ ] METRC live API sync (requires credentials)
- [ ] Native mobile apps (iOS/Android)
--- ---
## Documentation Status ## Quick Start
| Document | Status | Location | ```bash
|----------|--------|----------| # Clone and setup
| Constitution | ✅ Complete | `.specify/memory/constitution.md` | cd 777wolfpack
| Project Spec | ✅ Complete | `spec.yml` | docker-compose up -d
| Architecture | ✅ Complete | `docs/architecture.md` |
| Compliance Notes | ✅ Complete | `docs/compliance-notes-ca.md` |
| Backend README | ✅ Complete | `backend/README.md` |
| Frontend README | ✅ Complete | `frontend/README.md` |
| Phase 1 Plan | ✅ Complete | `plans/phase-1-foundation.md` |
| Week 1 Tasks | ✅ Complete | `plans/tasks-week-1-infrastructure.md` |
| API Documentation | ⬜ Not Started | TBD (OpenAPI/Swagger) |
| User Guide | ⬜ Not Started | TBD |
| Deployment Guide | ⬜ Not Started | TBD |
--- # Seed database
cd backend && npm run db:seed
## Risk Register # Access application
open https://777wolfpack.runfoo.run
```
| Risk | Severity | Probability | Mitigation | Status | ### Demo Credentials
|------|----------|-------------|------------|--------|
| Scope creep in Phase 1 | High | Medium | Strict adherence to spec; defer to Phase 2 | 🟢 Mitigated |
| Database schema changes | Medium | High | Use Prisma migrations; test thoroughly | 🟢 Mitigated |
| Mobile UX issues | High | Medium | Test on real devices early | 🟡 Monitor |
| Auth vulnerabilities | Critical | Low | Security audit; use established libraries | 🟢 Mitigated |
| Performance with large datasets | Medium | Medium | Pagination + indexes from start | 🟢 Mitigated |
| Team capacity | Medium | Medium | Clear task breakdown; realistic timeline | 🟢 Mitigated |
--- - **Admin**: `admin@777wolfpack.com` / `admin123`
- **Manager**: `manager@777wolfpack.com` / `manager123`
## Success Metrics - **Worker**: `worker@777wolfpack.com` / `worker123`
### Phase 1 Targets
**Functionality**:
- [ ] All Phase 1 features implemented
- [ ] All acceptance criteria met
- [ ] Zero critical bugs
**Quality**:
- [ ] 80%+ test coverage (backend and frontend)
- [ ] WCAG 2.1 AA compliance
- [ ] Zero security vulnerabilities (critical/high)
**Performance**:
- [ ] API response time < 200ms (p95)
- [ ] Page load time < 2s on 3G
- [ ] Lighthouse score > 90
**Documentation**:
- [ ] API documentation complete
- [ ] User guide complete
- [ ] Deployment guide complete
---
## Team & Roles
**Recommended Team Composition**:
- **1x Backend Developer**: Fastify, Prisma, PostgreSQL, Auth
- **1x Frontend Developer**: React, Tailwind, shadcn/ui, Mobile UX
- **1x Full-Stack Developer** (optional): Can support both sides
- **1x Product Manager** (part-time): Spec review, stakeholder communication
- **1x QA/Tester** (part-time): Testing, bug reporting
**Minimum Viable Team**:
- **1x Full-Stack Developer**: Can complete Phase 1 in 6 weeks solo
---
## Communication & Tracking
**Recommended Tools**:
- **Project Management**: GitHub Projects, Linear, or Jira
- **Communication**: Slack or Discord
- **Documentation**: Notion or Confluence
- **Code Repository**: GitHub or GitLab
- **CI/CD**: GitHub Actions or GitLab CI
**Meeting Cadence** (if team):
- **Daily Standup**: 15 min (async or sync)
- **Weekly Planning**: 1 hour (review tasks, plan next week)
- **Bi-Weekly Demo**: 30 min (show progress to stakeholders)
- **Retrospective**: 1 hour (end of each phase)
---
## Next Actions
### Immediate (This Week)
1. ✅ Review Phase 1 plan with team/stakeholders
2. ✅ Review Week 1 tasks
3. ⏭️ **Start TASK-001**: Initialize Backend Project
4. ⏭️ **Start TASK-006**: Initialize Frontend Project
5. ⏭️ **Start TASK-013**: Create Git Repository
### Short-Term (Next 2 Weeks)
1. Complete Week 1: Infrastructure Setup
2. Complete Week 2: Authentication & RBAC
3. Create Week 2 task breakdown
4. Set up project tracking (GitHub Projects)
### Medium-Term (Next 6 Weeks)
1. Complete Phase 1: Foundation
2. Deploy to staging environment
3. Conduct stakeholder demo
4. Plan Phase 2: Operations
--- ---
## Resources ## Resources
### Documentation - [Roadmap](docs/ROADMAP.md)
- [Constitution](.specify/memory/constitution.md)
- [Project Spec](spec.yml)
- [Architecture](docs/architecture.md) - [Architecture](docs/architecture.md)
- [Compliance Notes](docs/compliance-notes-ca.md) - [Compliance Notes](docs/compliance-notes-ca.md)
- [3D Viewer Refactor Plan](.agent/plans/3d_viewer_refactor.md)
### Plans - [Verification Guide](VERIFICATION_GUIDE.md)
- [Phase 1 Plan](plans/phase-1-foundation.md)
- [Week 1 Tasks](plans/tasks-week-1-infrastructure.md)
### Specs
- [Tasks and Scheduling](specs/tasks-and-scheduling.md)
- [Batches and Rooms](specs/batches-and-rooms.md)
- [Labor and Hours](specs/labor-and-hours.md)
- [Compliance and Docs](specs/compliance-and-docs.md)
- [Inventory and Materials](specs/inventory-and-materials.md)
- [Integrations and Hardware](specs/integrations-and-hardware.md)
- [Communications and Notifications](specs/communications-and-notifications.md)
--- ---
## Changelog **Status**: 🟢 DEMO READY
**Next Steps**: Smoke test deployment, prepare for stakeholder demo
### 2025-12-08
- ✅ Project initialized with Spec Kit
- ✅ Constitution created
- ✅ 7 feature specs written
- ✅ Architecture documented
- ✅ Phase 1 plan created
- ✅ Week 1 tasks defined
- ✅ Architecture decisions made (Fastify, Vite, shadcn/ui)
---
**Status**: 🟢 ON TRACK
**Next Milestone**: Week 1 Complete (TBD)
**Phase 1 Target**: 6 weeks from start

40
VERIFICATION_GUIDE.md Normal file
View file

@ -0,0 +1,40 @@
# 3D Facility Viewer & METRC Integration - Verification Guide
## 1. Feature Overview
We have integrated METRC plant tracking with the 3D facility viewer and added advanced data visualizations.
- **Deep Linking**: Click "View in 3D" from the METRC Dashboard to fly directly to a plant's location.
- **Plant History**: View a timeline of plant movements in the METRC Dashboard.
- **Data Overlays**: Toggle "Health", "Temperature", "Humidity", and "Yield" modes in the 3D viewer.
## 2. Verification Steps
### A. METRC Dashboard Integration
1. Navigate to `/metrc`.
2. Find a plant in the "Live Plants" table.
3. **Test History**: Click the **"History"** button.
- Verify a modal appears showing the plant's current location and movement log.
- Click **"Locate in 3D"** within the modal.
4. **Test Direct Link**: Click the **"View in 3D"** button (box icon) in the table row.
- Verify you are redirected to `/facility/3d`.
- Verify the camera automatically flies to the room containing the plant.
- Verify the specific plant is selected (popup overlay appears).
### B. 3D Data Visualization
1. Navigate to `/facility/3d`.
2. Look for the floating control panel on the **right side** of the screen.
3. Test the Modes:
- **Standard**: Default view, plants colored by stage (Veg/Flower).
- **Health**: Plants colored Green (Good), Yellow (Warning), Red (Critical). *Note: Uses simulated data for demo.*
- **Temp**: Rooms colored by temperature heatmap (Blue -> Red). Hover/Look for temperature labels.
- **VPD (Humidity)**: Rooms colored by humidity heatmap.
- **Yield**: Plants colored by maturity gradient.
4. **Legend**: Verify the legend at the top of the screen updates to reflect the active mode.
## 3. Configuration & Troubleshooting
- **Data Source**: The environment and health data are currently simulated (`getMockRoomEnv`, `getMockPlantHealth`) for demonstration purposes. To connect real sensors, update the `useEffect` hook in `Facility3DViewerPage.tsx` to fetch from your IoT API.
- **Missing Plants**: If a plant is not found when deep-linking, a warning is logged to the console, and the viewer stays at the default view. Ensure the `seed-plants.js` script has been run to populate the facility.

View file

@ -8,7 +8,7 @@ describe('CA Grow Ops Manager API Tests', () => {
describe('Health Check', () => { describe('Health Check', () => {
it('should return ok status', async () => { it('should return ok status', async () => {
const response = await fetch(`${API_BASE}/healthz`); const response = await fetch(`${API_BASE}/healthz`);
const data = await response.json(); const data = await response.json() as { status: string; timestamp: string };
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(data.status).toBe('ok'); expect(data.status).toBe('ok');
@ -52,10 +52,10 @@ describe('CA Grow Ops Manager API Tests', () => {
}); });
if (response.status === 200) { if (response.status === 200) {
const data = await response.json(); const data = await response.json() as { token: string; user?: { id: string } };
expect(data.token).toBeDefined(); expect(data.token).toBeDefined();
authToken = data.token; authToken = data.token;
testUserId = data.user?.id; testUserId = data.user?.id || '';
} }
}); });
}); });
@ -160,7 +160,7 @@ describe('CA Grow Ops Manager API Tests', () => {
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
const data = await response.json(); const data = await response.json() as { sizes: unknown };
expect(data.sizes).toBeDefined(); expect(data.sizes).toBeDefined();
}); });
}); });
@ -198,7 +198,7 @@ describe('CA Grow Ops Manager API Tests', () => {
}); });
expect(response.status).toBe(200); expect(response.status).toBe(200);
const data = await response.json(); const data = await response.json() as { transactions: unknown[] };
expect(data.transactions).toBeDefined(); expect(data.transactions).toBeDefined();
}); });

View file

@ -13,8 +13,8 @@
"@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.8", "@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-slot": "^1.2.4",
"@react-three/drei": "^10.7.7", "@react-three/drei": "9.107.2",
"@react-three/fiber": "^9.4.2", "@react-three/fiber": "8.16.8",
"axios": "^1.6.2", "axios": "^1.6.2",
"browser-image-compression": "^2.0.2", "browser-image-compression": "^2.0.2",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@ -32,7 +32,7 @@
"react-konva": "^18.2.10", "react-konva": "^18.2.10",
"react-router-dom": "^7.10.1", "react-router-dom": "^7.10.1",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"three": "^0.182.0", "three": "0.165.0",
"zustand": "^4.5.2" "zustand": "^4.5.2"
}, },
"devDependencies": { "devDependencies": {
@ -1183,9 +1183,9 @@
} }
}, },
"node_modules/@mediapipe/tasks-vision": { "node_modules/@mediapipe/tasks-vision": {
"version": "0.10.17", "version": "0.10.8",
"resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.8.tgz",
"integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", "integrity": "sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@monogrid/gainmap-js": { "node_modules/@monogrid/gainmap-js": {
@ -2375,39 +2375,115 @@
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@react-three/drei": { "node_modules/@react-spring/animated": {
"version": "10.7.7", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.7.tgz", "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.6.1.tgz",
"integrity": "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==", "integrity": "sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@react-spring/shared": "~9.6.1",
"@mediapipe/tasks-vision": "0.10.17", "@react-spring/types": "~9.6.1"
"@monogrid/gainmap-js": "^3.0.6",
"@use-gesture/react": "^10.3.1",
"camera-controls": "^3.1.0",
"cross-env": "^7.0.3",
"detect-gpu": "^5.0.56",
"glsl-noise": "^0.0.0",
"hls.js": "^1.5.17",
"maath": "^0.10.8",
"meshline": "^3.3.1",
"stats-gl": "^2.2.8",
"stats.js": "^0.17.0",
"suspend-react": "^0.1.3",
"three-mesh-bvh": "^0.8.3",
"three-stdlib": "^2.35.6",
"troika-three-text": "^0.52.4",
"tunnel-rat": "^0.1.2",
"use-sync-external-store": "^1.4.0",
"utility-types": "^3.11.0",
"zustand": "^5.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"@react-three/fiber": "^9.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
"react": "^19", }
"react-dom": "^19", },
"three": ">=0.159" "node_modules/@react-spring/core": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.6.1.tgz",
"integrity": "sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==",
"license": "MIT",
"dependencies": {
"@react-spring/animated": "~9.6.1",
"@react-spring/rafz": "~9.6.1",
"@react-spring/shared": "~9.6.1",
"@react-spring/types": "~9.6.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-spring/donate"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@react-spring/rafz": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.6.1.tgz",
"integrity": "sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==",
"license": "MIT"
},
"node_modules/@react-spring/shared": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.6.1.tgz",
"integrity": "sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==",
"license": "MIT",
"dependencies": {
"@react-spring/rafz": "~9.6.1",
"@react-spring/types": "~9.6.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@react-spring/three": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.6.1.tgz",
"integrity": "sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==",
"license": "MIT",
"dependencies": {
"@react-spring/animated": "~9.6.1",
"@react-spring/core": "~9.6.1",
"@react-spring/shared": "~9.6.1",
"@react-spring/types": "~9.6.1"
},
"peerDependencies": {
"@react-three/fiber": ">=6.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"three": ">=0.126"
}
},
"node_modules/@react-spring/types": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.6.1.tgz",
"integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==",
"license": "MIT"
},
"node_modules/@react-three/drei": {
"version": "9.107.2",
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.107.2.tgz",
"integrity": "sha512-MQqRhq3bFKkYuhwp812JwdcYRy/601+jokri2m+PmuuWGy6Xi9n001pzeH47iy1Gb8KCiGHAilGXiXF87A/t4A==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@mediapipe/tasks-vision": "0.10.8",
"@monogrid/gainmap-js": "^3.0.5",
"@react-spring/three": "~9.6.1",
"@use-gesture/react": "^10.2.24",
"camera-controls": "^2.4.2",
"cross-env": "^7.0.3",
"detect-gpu": "^5.0.28",
"glsl-noise": "^0.0.0",
"hls.js": "1.3.5",
"maath": "^0.10.7",
"meshline": "^3.1.6",
"react-composer": "^5.0.3",
"stats-gl": "^2.0.0",
"stats.js": "^0.17.0",
"suspend-react": "^0.1.3",
"three-mesh-bvh": "^0.7.0",
"three-stdlib": "^2.29.9",
"troika-three-text": "^0.49.0",
"tunnel-rat": "^0.1.2",
"utility-types": "^3.10.0",
"uuid": "^9.0.1",
"zustand": "^3.7.1"
},
"peerDependencies": {
"@react-three/fiber": ">=8.0",
"react": ">=18.0",
"react-dom": ">=18.0",
"three": ">=0.137"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"react-dom": { "react-dom": {
@ -2416,62 +2492,49 @@
} }
}, },
"node_modules/@react-three/drei/node_modules/zustand": { "node_modules/@react-three/drei/node_modules/zustand": {
"version": "5.0.9", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.9.tgz", "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12.20.0" "node": ">=12.7.0"
}, },
"peerDependencies": { "peerDependencies": {
"@types/react": ">=18.0.0", "react": ">=16.8"
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": { "react": {
"optional": true "optional": true
},
"use-sync-external-store": {
"optional": true
} }
} }
}, },
"node_modules/@react-three/fiber": { "node_modules/@react-three/fiber": {
"version": "9.4.2", "version": "8.16.8",
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.4.2.tgz", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.16.8.tgz",
"integrity": "sha512-H4B4+FDNHpvIb4FmphH4ubxOfX5bxmfOw0+3pkQwR9u9wFiyMS7wUDkNn0m4RqQuiLWeia9jfN1eBvtyAVGEog==", "integrity": "sha512-Lc8fjATtvQEfSd8d5iKdbpHtRm/aPMeFj7jQvp6TNHfpo8IQTW3wwcE1ZMrGGoUH+w2mnyS+0MK1NLPLnuzGkQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.17.8", "@babel/runtime": "^7.17.8",
"@types/react-reconciler": "^0.32.0", "@types/react-reconciler": "^0.26.7",
"@types/webxr": "*", "@types/webxr": "*",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"its-fine": "^2.0.0", "its-fine": "^1.0.6",
"react-reconciler": "^0.31.0", "react-reconciler": "^0.27.0",
"react-use-measure": "^2.1.7", "react-use-measure": "^2.1.1",
"scheduler": "^0.25.0", "scheduler": "^0.21.0",
"suspend-react": "^0.1.3", "suspend-react": "^0.1.3",
"use-sync-external-store": "^1.4.0", "zustand": "^3.7.1"
"zustand": "^5.0.3"
}, },
"peerDependencies": { "peerDependencies": {
"expo": ">=43.0", "expo": ">=43.0",
"expo-asset": ">=8.4", "expo-asset": ">=8.4",
"expo-file-system": ">=11.0", "expo-file-system": ">=11.0",
"expo-gl": ">=11.0", "expo-gl": ">=11.0",
"react": "^19.0.0", "react": ">=18.0",
"react-dom": "^19.0.0", "react-dom": ">=18.0",
"react-native": ">=0.78", "react-native": ">=0.64",
"three": ">=0.156" "three": ">=0.133"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"expo": { "expo": {
@ -2495,82 +2558,53 @@
} }
}, },
"node_modules/@react-three/fiber/node_modules/@types/react-reconciler": { "node_modules/@react-three/fiber/node_modules/@types/react-reconciler": {
"version": "0.32.3", "version": "0.26.7",
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.32.3.tgz", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz",
"integrity": "sha512-cMi5ZrLG7UtbL7LTK6hq9w/EZIRk4Mf1Z5qHoI+qBh7/WkYkFXQ7gOto2yfUvPzF5ERMAhaXS5eTQ2SAnHjLzA==", "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@react-three/fiber/node_modules/its-fine": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz",
"integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/react-reconciler": "^0.28.9"
},
"peerDependencies": {
"react": "^19.0.0"
}
},
"node_modules/@react-three/fiber/node_modules/its-fine/node_modules/@types/react-reconciler": {
"version": "0.28.9",
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
"integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@react-three/fiber/node_modules/react-reconciler": { "node_modules/@react-three/fiber/node_modules/react-reconciler": {
"version": "0.31.0", "version": "0.27.0",
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.31.0.tgz", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz",
"integrity": "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==", "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"scheduler": "^0.25.0" "loose-envify": "^1.1.0",
"scheduler": "^0.21.0"
}, },
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^19.0.0" "react": "^18.0.0"
} }
}, },
"node_modules/@react-three/fiber/node_modules/scheduler": { "node_modules/@react-three/fiber/node_modules/scheduler": {
"version": "0.25.0", "version": "0.21.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz",
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==",
"license": "MIT" "license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
}, },
"node_modules/@react-three/fiber/node_modules/zustand": { "node_modules/@react-three/fiber/node_modules/zustand": {
"version": "5.0.9", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.9.tgz", "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz",
"integrity": "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12.20.0" "node": ">=12.7.0"
}, },
"peerDependencies": { "peerDependencies": {
"@types/react": ">=18.0.0", "react": ">=16.8"
"immer": ">=9.0.6",
"react": ">=18.0.0",
"use-sync-external-store": ">=1.2.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": { "react": {
"optional": true "optional": true
},
"use-sync-external-store": {
"optional": true
} }
} }
}, },
@ -3105,7 +3139,6 @@
"version": "15.7.15", "version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/qrcode": { "node_modules/@types/qrcode": {
@ -3122,7 +3155,6 @@
"version": "18.3.27", "version": "18.3.27",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
@ -3133,7 +3165,7 @@
"version": "18.3.7", "version": "18.3.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"dev": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"@types/react": "^18.0.0" "@types/react": "^18.0.0"
@ -4025,14 +4057,10 @@
} }
}, },
"node_modules/camera-controls": { "node_modules/camera-controls": {
"version": "3.1.2", "version": "2.10.1",
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz", "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.10.1.tgz",
"integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==", "integrity": "sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==",
"license": "MIT", "license": "MIT",
"engines": {
"node": ">=22.0.0",
"npm": ">=10.5.1"
},
"peerDependencies": { "peerDependencies": {
"three": ">=0.126.1" "three": ">=0.126.1"
} }
@ -4342,7 +4370,6 @@
"version": "3.2.3", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/data-urls": { "node_modules/data-urls": {
@ -5499,9 +5526,9 @@
} }
}, },
"node_modules/hls.js": { "node_modules/hls.js": {
"version": "1.6.15", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.3.5.tgz",
"integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", "integrity": "sha512-uybAvKS6uDe0MnWNEPnO0krWVr+8m2R0hJ/viql8H3MVK+itq8gGQuIYoFHL3rECkIpNH98Lw8YuuWMKZxp3Ew==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/html-encoding-sniffer": { "node_modules/html-encoding-sniffer": {
@ -6655,7 +6682,6 @@
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -7200,6 +7226,23 @@
"lie": "^3.0.2" "lie": "^3.0.2"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/prop-types/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/proxy-from-env": { "node_modules/proxy-from-env": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@ -7295,6 +7338,18 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-composer": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz",
"integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.6.0"
},
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
@ -8268,18 +8323,18 @@
} }
}, },
"node_modules/three": { "node_modules/three": {
"version": "0.182.0", "version": "0.165.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", "resolved": "https://registry.npmjs.org/three/-/three-0.165.0.tgz",
"integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", "integrity": "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/three-mesh-bvh": { "node_modules/three-mesh-bvh": {
"version": "0.8.3", "version": "0.7.6",
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.6.tgz",
"integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==", "integrity": "sha512-rCjsnxEqR9r1/C/lCqzGLS67NDty/S/eT6rAJfDvsanrIctTWdNoR4ZOGWewCB13h1QkVo2BpmC0wakj1+0m8A==",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"three": ">= 0.159.0" "three": ">= 0.151.0"
} }
}, },
"node_modules/three-stdlib": { "node_modules/three-stdlib": {
@ -8423,14 +8478,14 @@
} }
}, },
"node_modules/troika-three-text": { "node_modules/troika-three-text": {
"version": "0.52.4", "version": "0.49.1",
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.49.1.tgz",
"integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", "integrity": "sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bidi-js": "^1.0.2", "bidi-js": "^1.0.2",
"troika-three-utils": "^0.52.4", "troika-three-utils": "^0.49.0",
"troika-worker-utils": "^0.52.0", "troika-worker-utils": "^0.49.0",
"webgl-sdf-generator": "1.1.1" "webgl-sdf-generator": "1.1.1"
}, },
"peerDependencies": { "peerDependencies": {
@ -8438,18 +8493,18 @@
} }
}, },
"node_modules/troika-three-utils": { "node_modules/troika-three-utils": {
"version": "0.52.4", "version": "0.49.0",
"resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.49.0.tgz",
"integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", "integrity": "sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"three": ">=0.125.0" "three": ">=0.125.0"
} }
}, },
"node_modules/troika-worker-utils": { "node_modules/troika-worker-utils": {
"version": "0.52.0", "version": "0.49.0",
"resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.49.0.tgz",
"integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", "integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/ts-api-utils": { "node_modules/ts-api-utils": {
@ -8527,7 +8582,7 @@
"version": "5.9.3", "version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -8681,6 +8736,19 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/uzip": { "node_modules/uzip": {
"version": "0.20201231.0", "version": "0.20201231.0",
"resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz", "resolved": "https://registry.npmjs.org/uzip/-/uzip-0.20201231.0.tgz",

View file

@ -128,7 +128,7 @@ export const NAV_SECTIONS: NavSection[] = [
{ id: 'audit', label: 'Audit Log', path: '/compliance/audit', icon: ClipboardList }, { id: 'audit', label: 'Audit Log', path: '/compliance/audit', icon: ClipboardList },
{ id: 'documents', label: 'SOP Library', path: '/compliance/documents', icon: FileText }, { id: 'documents', label: 'SOP Library', path: '/compliance/documents', icon: FileText },
{ id: 'metrc', label: 'METRC Integration', path: '/metrc', icon: Cloud, minRole: 'MANAGER' }, { id: 'metrc', label: 'METRC Integration', path: '/metrc', icon: Cloud, minRole: 'MANAGER' },
{ id: 'facility-3d', label: '3D Facility View', path: '/facility-3d', icon: Grid3X3, minRole: 'MANAGER' }, { id: 'facility-3d', label: '3D Facility View', path: '/facility/3d', icon: Grid3X3, minRole: 'MANAGER' },
{ id: 'layout', label: 'Layout Designer', path: '/layout-designer', icon: Grid3X3, minRole: 'ADMIN' }, { id: 'layout', label: 'Layout Designer', path: '/layout-designer', icon: Grid3X3, minRole: 'ADMIN' },
] ]
}, },

View file

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom'; import { useParams, Link } from 'react-router-dom';
import { Shield, Clock, MapPin, Loader, AlertTriangle, User, RotateCcw, QrCode, LogOut } from 'lucide-react'; import { Shield, Clock, MapPin, Loader, AlertTriangle, User, RotateCcw, QrCode, LogOut, LayoutDashboard } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { visitorsApi, Visitor, VisitorLog } from '../lib/visitorsApi'; import { visitorsApi, Visitor, VisitorLog } from '../lib/visitorsApi';
@ -262,10 +262,19 @@ export default function BadgePage() {
</div> </div>
</div> </div>
{/* Bottom Branding */} {/* Bottom Navigation */}
<p className="text-slate-600 text-xs mt-8 text-center"> <div className="mt-8 flex flex-col items-center gap-3">
<Link
to="/"
className="flex items-center gap-2 text-slate-400 hover:text-emerald-400 text-sm transition-colors px-4 py-2 rounded-lg hover:bg-white/5"
>
<LayoutDashboard size={16} />
<span>Dashboard</span>
</Link>
<p className="text-slate-600 text-xs text-center">
Digital Badge powered by 777 Wolfpack Grow Ops Manager Digital Badge powered by 777 Wolfpack Grow Ops Manager
</p> </p>
</div> </div>
</div>
); );
} }

View file

@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { QRCodeSVG as QRCode } from 'qrcode.react'; import { QRCodeSVG as QRCode } from 'qrcode.react';
import { User, Building, Clock, CheckCircle, XCircle, UserPlus, LogOut, Search, Shield, AlertTriangle, Camera, Trash2, Download } from 'lucide-react'; import { User, Building, Clock, CheckCircle, XCircle, UserPlus, LogOut, Search, Shield, AlertTriangle, Camera, Trash2, Download, LayoutDashboard } from 'lucide-react';
import { visitorsApi, Visitor, ActiveVisitor } from '../lib/visitorsApi'; import { visitorsApi, Visitor, ActiveVisitor } from '../lib/visitorsApi';
type KioskMode = 'home' | 'new-visitor' | 'returning' | 'check-in' | 'check-out' | 'success'; type KioskMode = 'home' | 'new-visitor' | 'returning' | 'check-in' | 'check-out' | 'success';
@ -221,10 +222,19 @@ export default function VisitorKioskPage() {
<p className="text-xs text-slate-400">777 Wolfpack Facility</p> <p className="text-xs text-slate-400">777 Wolfpack Facility</p>
</div> </div>
</div> </div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 text-slate-400 text-sm"> <div className="flex items-center gap-2 text-slate-400 text-sm">
<Clock size={16} /> <Clock size={16} />
<span>{new Date().toLocaleTimeString()}</span> <span>{new Date().toLocaleTimeString()}</span>
</div> </div>
<Link
to="/"
className="flex items-center gap-2 text-slate-400 hover:text-emerald-400 text-sm transition-colors px-3 py-1.5 rounded-lg hover:bg-white/5"
>
<LayoutDashboard size={16} />
<span className="hidden sm:inline">Dashboard</span>
</Link>
</div>
</div> </div>
</header> </header>