From d156569d9958b5e98f5ee9fcb6155a63a73b4590 Mon Sep 17 00:00:00 2001 From: fullsizemalt <106900403+fullsizemalt@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:13:38 -0800 Subject: [PATCH] feat: Daily Walkthrough Frontend - Start + Reservoir Checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎨 Frontend UI Implementation (Phase 1.5) 📁 Files Created: - frontend/src/pages/DailyWalkthroughPage.tsx - frontend/src/components/walkthrough/ReservoirChecklist.tsx ✨ Features: - Mobile-first walkthrough start screen - 777 Wolfpack branding - Progress tracking - Visual tank level indicator - Touch-friendly slider (44px+ targets) - Auto status detection (OK/LOW/CRITICAL) - Color-coded status badges - Notes field - Photo upload placeholder - Responsive design (mobile → tablet → desktop) 📱 Mobile Optimizations: - Large tap targets (56px buttons) - Visual feedback (active states) - Bottom navigation on mobile - Gradient backgrounds - Backdrop blur effects - Touch-friendly sliders 🎨 UX Features: - Step-by-step wizard - Progress bar - Tank-by-tank workflow - Auto-save ready - Back navigation - Clear status indicators ⏭️ Next: Irrigation + Plant Health checklists Status: 40% Frontend Complete --- docs/API-WALKTHROUGH.md | 379 ++++++++++++++++++ .../walkthrough/ReservoirChecklist.tsx | 206 ++++++++++ frontend/src/pages/DailyWalkthroughPage.tsx | 174 ++++++++ 3 files changed, 759 insertions(+) create mode 100644 docs/API-WALKTHROUGH.md create mode 100644 frontend/src/components/walkthrough/ReservoirChecklist.tsx create mode 100644 frontend/src/pages/DailyWalkthroughPage.tsx diff --git a/docs/API-WALKTHROUGH.md b/docs/API-WALKTHROUGH.md new file mode 100644 index 0000000..3daa3ad --- /dev/null +++ b/docs/API-WALKTHROUGH.md @@ -0,0 +1,379 @@ +# Daily Walkthrough API Documentation + +**Base URL**: `/api/walkthroughs` +**Authentication**: Required (JWT Bearer token) + +--- + +## Endpoints + +### 1. Start New Walkthrough + +**POST** `/api/walkthroughs` + +**Request Body**: + +```json +{ + "date": "2025-12-09T08:00:00Z" // optional, defaults to now +} +``` + +**Response** (201): + +```json +{ + "id": "uuid", + "date": "2025-12-09T08:00:00Z", + "completedBy": "user-uuid", + "startTime": "2025-12-09T08:00:00Z", + "endTime": null, + "status": "IN_PROGRESS", + "user": { + "id": "user-uuid", + "name": "Facility Owner", + "email": "admin@runfoo.run", + "role": "OWNER" + }, + "reservoirChecks": [], + "irrigationChecks": [], + "plantHealthChecks": [], + "createdAt": "2025-12-09T08:00:00Z", + "updatedAt": "2025-12-09T08:00:00Z" +} +``` + +--- + +### 2. List Walkthroughs + +**GET** `/api/walkthroughs` + +**Query Parameters**: + +- `status` - Filter by status (`IN_PROGRESS`, `COMPLETED`, `INCOMPLETE`) +- `userId` - Filter by user ID +- `startDate` - Filter by start date (ISO 8601) +- `endDate` - Filter by end date (ISO 8601) + +**Example**: + +``` +GET /api/walkthroughs?status=COMPLETED&startDate=2025-12-01&endDate=2025-12-09 +``` + +**Response** (200): + +```json +[ + { + "id": "uuid", + "date": "2025-12-09T08:00:00Z", + "completedBy": "user-uuid", + "startTime": "2025-12-09T08:00:00Z", + "endTime": "2025-12-09T08:25:00Z", + "status": "COMPLETED", + "user": { ... }, + "reservoirChecks": [ ... ], + "irrigationChecks": [ ... ], + "plantHealthChecks": [ ... ] + } +] +``` + +--- + +### 3. Get Walkthrough Detail + +**GET** `/api/walkthroughs/:id` + +**Response** (200): + +```json +{ + "id": "uuid", + "date": "2025-12-09T08:00:00Z", + "completedBy": "user-uuid", + "startTime": "2025-12-09T08:00:00Z", + "endTime": null, + "status": "IN_PROGRESS", + "user": { ... }, + "reservoirChecks": [ ... ], + "irrigationChecks": [ ... ], + "plantHealthChecks": [ ... ] +} +``` + +**Error** (404): + +```json +{ + "message": "Walkthrough not found" +} +``` + +--- + +### 4. Complete Walkthrough + +**POST** `/api/walkthroughs/:id/complete` + +**Response** (200): + +```json +{ + "id": "uuid", + "status": "COMPLETED", + "endTime": "2025-12-09T08:25:00Z", + ... +} +``` + +--- + +### 5. Add Reservoir Check + +**POST** `/api/walkthroughs/:id/reservoir-checks` + +**Request Body**: + +```json +{ + "tankName": "Veg Tank 1", + "tankType": "VEG", + "levelPercent": 85, + "status": "OK", + "photoUrl": "https://...", + "notes": "All good" +} +``` + +**Field Validation**: + +- `tankName`: string (required) +- `tankType`: `"VEG"` | `"FLOWER"` (required) +- `levelPercent`: number 0-100 (required) +- `status`: `"OK"` | `"LOW"` | `"CRITICAL"` (required) +- `photoUrl`: string (optional) +- `notes`: string (optional) + +**Response** (201): + +```json +{ + "id": "uuid", + "walkthroughId": "walkthrough-uuid", + "tankName": "Veg Tank 1", + "tankType": "VEG", + "levelPercent": 85, + "status": "OK", + "photoUrl": "https://...", + "notes": "All good", + "createdAt": "2025-12-09T08:05:00Z" +} +``` + +--- + +### 6. Add Irrigation Check + +**POST** `/api/walkthroughs/:id/irrigation-checks` + +**Request Body**: + +```json +{ + "zoneName": "Veg Upstairs", + "drippersTotal": 48, + "drippersWorking": 47, + "drippersFailed": ["A-12"], + "waterFlow": true, + "nutrientsMixed": true, + "scheduleActive": true, + "photoUrl": "https://...", + "issues": "Dripper A-12 clogged" +} +``` + +**Field Validation**: + +- `zoneName`: string (required) - e.g., "Veg Upstairs", "Flower Downstairs" +- `drippersTotal`: number (required) +- `drippersWorking`: number (required) +- `drippersFailed`: string[] (optional) - array of dripper IDs +- `waterFlow`: boolean (required) +- `nutrientsMixed`: boolean (required) +- `scheduleActive`: boolean (required) +- `photoUrl`: string (optional) +- `issues`: string (optional) + +**Response** (201): + +```json +{ + "id": "uuid", + "walkthroughId": "walkthrough-uuid", + "zoneName": "Veg Upstairs", + "drippersTotal": 48, + "drippersWorking": 47, + "drippersFailed": "[\"A-12\"]", + "waterFlow": true, + "nutrientsMixed": true, + "scheduleActive": true, + "photoUrl": "https://...", + "issues": "Dripper A-12 clogged", + "createdAt": "2025-12-09T08:10:00Z" +} +``` + +--- + +### 7. Add Plant Health Check + +**POST** `/api/walkthroughs/:id/plant-health-checks` + +**Request Body**: + +```json +{ + "zoneName": "Flower Upstairs", + "healthStatus": "GOOD", + "pestsObserved": false, + "pestType": null, + "waterAccess": "OK", + "foodAccess": "OK", + "flaggedForAttention": false, + "issuePhotoUrl": null, + "referencePhotoUrl": "https://...", + "notes": "All plants healthy" +} +``` + +**Field Validation**: + +- `zoneName`: string (required) +- `healthStatus`: `"GOOD"` | `"FAIR"` | `"NEEDS_ATTENTION"` (required) +- `pestsObserved`: boolean (required) +- `pestType`: string (optional) - required if `pestsObserved` is true +- `waterAccess`: `"OK"` | `"ISSUES"` (required) +- `foodAccess`: `"OK"` | `"ISSUES"` (required) +- `flaggedForAttention`: boolean (optional, defaults to false) +- `issuePhotoUrl`: string (optional) +- `referencePhotoUrl`: string (optional) +- `notes`: string (optional) + +**Response** (201): + +```json +{ + "id": "uuid", + "walkthroughId": "walkthrough-uuid", + "zoneName": "Flower Upstairs", + "healthStatus": "GOOD", + "pestsObserved": false, + "pestType": null, + "waterAccess": "OK", + "foodAccess": "OK", + "flaggedForAttention": false, + "issuePhotoUrl": null, + "referencePhotoUrl": "https://...", + "notes": "All plants healthy", + "createdAt": "2025-12-09T08:15:00Z" +} +``` + +--- + +## Error Responses + +### 401 Unauthorized + +```json +{ + "message": "Unauthorized" +} +``` + +### 404 Not Found + +```json +{ + "message": "Walkthrough not found" +} +``` + +### 500 Internal Server Error + +```json +{ + "message": "Failed to create walkthrough" +} +``` + +--- + +## Example Workflow + +### Complete Morning Walkthrough + +```bash +# 1. Start walkthrough +curl -X POST https://777wolfpack.runfoo.run/api/walkthroughs \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{}' + +# Response: { "id": "walk-123", ... } + +# 2. Add reservoir checks (4 tanks) +curl -X POST https://777wolfpack.runfoo.run/api/walkthroughs/walk-123/reservoir-checks \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "tankName": "Veg Tank 1", + "tankType": "VEG", + "levelPercent": 85, + "status": "OK" + }' + +# 3. Add irrigation checks (4 zones) +curl -X POST https://777wolfpack.runfoo.run/api/walkthroughs/walk-123/irrigation-checks \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "zoneName": "Veg Upstairs", + "drippersTotal": 48, + "drippersWorking": 48, + "drippersFailed": [], + "waterFlow": true, + "nutrientsMixed": true, + "scheduleActive": true + }' + +# 4. Add plant health checks (4 zones) +curl -X POST https://777wolfpack.runfoo.run/api/walkthroughs/walk-123/plant-health-checks \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "zoneName": "Veg Upstairs", + "healthStatus": "GOOD", + "pestsObserved": false, + "waterAccess": "OK", + "foodAccess": "OK" + }' + +# 5. Complete walkthrough +curl -X POST https://777wolfpack.runfoo.run/api/walkthroughs/walk-123/complete \ + -H "Authorization: Bearer $TOKEN" +``` + +--- + +## Notes + +- All endpoints require authentication +- User is automatically attributed from JWT token +- Photos are stored as URLs (upload endpoint TBD) +- Failed drippers are stored as JSON string +- Cascade delete: deleting walkthrough deletes all checks +- Timestamps are UTC ISO 8601 format diff --git a/frontend/src/components/walkthrough/ReservoirChecklist.tsx b/frontend/src/components/walkthrough/ReservoirChecklist.tsx new file mode 100644 index 0000000..76116ed --- /dev/null +++ b/frontend/src/components/walkthrough/ReservoirChecklist.tsx @@ -0,0 +1,206 @@ +import { useState } from 'react'; + +interface Tank { + name: string; + type: 'VEG' | 'FLOWER'; +} + +interface ReservoirCheckData { + tankName: string; + tankType: 'VEG' | 'FLOWER'; + levelPercent: number; + status: 'OK' | 'LOW' | 'CRITICAL'; + photoUrl?: string; + notes?: string; +} + +interface ReservoirChecklistProps { + onComplete: (checks: ReservoirCheckData[]) => void; + onBack: () => void; +} + +export default function ReservoirChecklist({ onComplete, onBack }: ReservoirChecklistProps) { + const tanks: Tank[] = [ + { name: 'Veg Tank 1', type: 'VEG' }, + { name: 'Veg Tank 2', type: 'VEG' }, + { name: 'Flower Tank 1', type: 'FLOWER' }, + { name: 'Flower Tank 2', type: 'FLOWER' }, + ]; + + const [checks, setChecks] = useState>(new Map()); + const [currentTankIndex, setCurrentTankIndex] = useState(0); + const [levelPercent, setLevelPercent] = useState(100); + const [notes, setNotes] = useState(''); + + const currentTank = tanks[currentTankIndex]; + const isLastTank = currentTankIndex === tanks.length - 1; + + const getStatus = (level: number): 'OK' | 'LOW' | 'CRITICAL' => { + if (level >= 70) return 'OK'; + if (level >= 30) return 'LOW'; + return 'CRITICAL'; + }; + + const handleNext = () => { + // Save current check + const checkData: ReservoirCheckData = { + tankName: currentTank.name, + tankType: currentTank.type, + levelPercent, + status: getStatus(levelPercent), + notes: notes || undefined, + }; + + const newChecks = new Map(checks); + newChecks.set(currentTank.name, checkData); + setChecks(newChecks); + + if (isLastTank) { + // Complete + onComplete(Array.from(newChecks.values())); + } else { + // Next tank + setCurrentTankIndex(currentTankIndex + 1); + setLevelPercent(100); + setNotes(''); + } + }; + + const status = getStatus(levelPercent); + const statusColor = { + OK: 'bg-emerald-500', + LOW: 'bg-yellow-500', + CRITICAL: 'bg-red-500', + }[status]; + + const statusText = { + OK: 'Good', + LOW: 'Low - Needs Refill', + CRITICAL: 'Critical - Refill Now!', + }[status]; + + return ( +
+
+ {/* Header */} +
+
+ +
+

+ Reservoir Checks +

+

+ Tank {currentTankIndex + 1} of {tanks.length} +

+
+
+ + {/* Progress */} +
+
+
+
+ + {/* Tank Card */} +
+ {/* Tank Info */} +
+
💧
+

+ {currentTank.name} +

+

+ {currentTank.type === 'VEG' ? 'Vegetative' : 'Flowering'} Tank +

+
+ + {/* Level Slider */} +
+ + + {/* Visual Level Indicator */} +
+
+
+
+
+ + {levelPercent}% + +
+
+ + {/* Slider */} + setLevelPercent(parseInt(e.target.value))} + className="w-full h-3 bg-slate-200 dark:bg-slate-700 rounded-lg appearance-none cursor-pointer accent-emerald-600" + /> + + {/* Status Badge */} +
+ {statusText} +
+
+ + {/* Notes */} +
+ +