feat(sprint-6): Phase 5 — Full grow calendar (sensors, photos, feeding, harvest traceability)
- V9 migration: grow_entries, grow_stage_logs, sensor_readings, grow_photos, feeding_logs - 5 entities + GrowStage enum (7 stages) + SensorReadingType enum - GrowCalendarService: CRUD + stage advancement + harvest-to-batch linking - GrowCalendarController: 8 endpoints (/api/v1/grow/*) - Frontend: /grow list + /grow/[id] detail (timeline, sensor charts, photo gallery, feeding log) - Sensor chart (Recharts line: temp + humidity over time) - Harvest completion links grow entry → batch (full traceability) - React Query hooks for all grow operations - Full i18n (de/en) with 7 grow stage labels - Sidebar navigation updated with Anbau/Grow entry
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
import type { GrowEntry, GrowEntryDetail } from "@/services/grow"
|
||||
|
||||
function daysAgo(days: number): string {
|
||||
const d = new Date()
|
||||
d.setDate(d.getDate() - days)
|
||||
return d.toISOString()
|
||||
}
|
||||
|
||||
function daysFromNow(days: number): string {
|
||||
const d = new Date()
|
||||
d.setDate(d.getDate() + days)
|
||||
return d.toISOString()
|
||||
}
|
||||
|
||||
export const mockGrowEntries: GrowEntry[] = [
|
||||
{
|
||||
id: "grow-001",
|
||||
name: "Amnesia Haze Runde 3",
|
||||
strainId: "s-001",
|
||||
status: "FLOWERING",
|
||||
startedAt: daysAgo(55),
|
||||
expectedHarvestAt: daysFromNow(25),
|
||||
actualHarvestAt: null,
|
||||
harvestedGrams: null,
|
||||
linkedBatchId: null,
|
||||
notes: "Sehr kräftiger Wuchs, 4 Pflanzen",
|
||||
},
|
||||
{
|
||||
id: "grow-002",
|
||||
name: "White Widow Indoor",
|
||||
strainId: "s-002",
|
||||
status: "DRYING",
|
||||
startedAt: daysAgo(95),
|
||||
expectedHarvestAt: daysAgo(5),
|
||||
actualHarvestAt: daysAgo(5),
|
||||
harvestedGrams: 320,
|
||||
linkedBatchId: null,
|
||||
notes: "Ernte war ertragreich, jetzt in Trocknung",
|
||||
},
|
||||
{
|
||||
id: "grow-003",
|
||||
name: "Northern Lights Micro",
|
||||
strainId: "s-003",
|
||||
status: "COMPLETE",
|
||||
startedAt: daysAgo(140),
|
||||
expectedHarvestAt: daysAgo(40),
|
||||
actualHarvestAt: daysAgo(42),
|
||||
harvestedGrams: 185.5,
|
||||
linkedBatchId: "b-001",
|
||||
notes: "Fertig, verknüpft mit Charge B-2024-003",
|
||||
},
|
||||
]
|
||||
|
||||
export function mockGrowDetail(id: string): GrowEntryDetail {
|
||||
const entry = mockGrowEntries.find((e) => e.id === id) ?? mockGrowEntries[0]
|
||||
return {
|
||||
...entry,
|
||||
stages: [
|
||||
{
|
||||
id: "stg-1",
|
||||
stage: "SEEDLING",
|
||||
startedAt: entry.startedAt,
|
||||
endedAt: daysAgo(40),
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: "stg-2",
|
||||
stage: "VEGETATIVE",
|
||||
startedAt: daysAgo(40),
|
||||
endedAt: daysAgo(20),
|
||||
notes: "Topped einmal",
|
||||
},
|
||||
{
|
||||
id: "stg-3",
|
||||
stage: "FLOWERING",
|
||||
startedAt: daysAgo(20),
|
||||
endedAt: null,
|
||||
notes: null,
|
||||
},
|
||||
],
|
||||
sensors: [
|
||||
{
|
||||
id: "sr-1",
|
||||
readingType: "TEMPERATURE",
|
||||
value: 24.5,
|
||||
unit: "°C",
|
||||
recordedAt: daysAgo(1),
|
||||
},
|
||||
{
|
||||
id: "sr-2",
|
||||
readingType: "HUMIDITY",
|
||||
value: 55,
|
||||
unit: "%",
|
||||
recordedAt: daysAgo(1),
|
||||
},
|
||||
{
|
||||
id: "sr-3",
|
||||
readingType: "TEMPERATURE",
|
||||
value: 23.8,
|
||||
unit: "°C",
|
||||
recordedAt: daysAgo(2),
|
||||
},
|
||||
{
|
||||
id: "sr-4",
|
||||
readingType: "HUMIDITY",
|
||||
value: 58,
|
||||
unit: "%",
|
||||
recordedAt: daysAgo(2),
|
||||
},
|
||||
{
|
||||
id: "sr-5",
|
||||
readingType: "TEMPERATURE",
|
||||
value: 25.1,
|
||||
unit: "°C",
|
||||
recordedAt: daysAgo(3),
|
||||
},
|
||||
{
|
||||
id: "sr-6",
|
||||
readingType: "HUMIDITY",
|
||||
value: 52,
|
||||
unit: "%",
|
||||
recordedAt: daysAgo(3),
|
||||
},
|
||||
{
|
||||
id: "sr-7",
|
||||
readingType: "PH",
|
||||
value: 6.2,
|
||||
unit: "pH",
|
||||
recordedAt: daysAgo(2),
|
||||
},
|
||||
{
|
||||
id: "sr-8",
|
||||
readingType: "EC",
|
||||
value: 1.8,
|
||||
unit: "mS/cm",
|
||||
recordedAt: daysAgo(2),
|
||||
},
|
||||
],
|
||||
photos: [
|
||||
{
|
||||
id: "ph-1",
|
||||
filePath: "/uploads/grow-001/week6.jpg",
|
||||
caption: "Woche 6 — Blüte beginnt",
|
||||
takenAt: daysAgo(5),
|
||||
},
|
||||
{
|
||||
id: "ph-2",
|
||||
filePath: "/uploads/grow-001/week4.jpg",
|
||||
caption: "Woche 4 — Vegetativ",
|
||||
takenAt: daysAgo(20),
|
||||
},
|
||||
],
|
||||
feedings: [
|
||||
{
|
||||
id: "fl-1",
|
||||
nutrientName: "BioBizz Bloom",
|
||||
amountMl: 4,
|
||||
waterLiters: 2,
|
||||
phAfter: 6.3,
|
||||
ecAfter: 1.9,
|
||||
fedAt: daysAgo(1),
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: "fl-2",
|
||||
nutrientName: "BioBizz Top-Max",
|
||||
amountMl: 2,
|
||||
waterLiters: 2,
|
||||
phAfter: 6.1,
|
||||
ecAfter: 1.7,
|
||||
fedAt: daysAgo(3),
|
||||
notes: null,
|
||||
},
|
||||
{
|
||||
id: "fl-3",
|
||||
nutrientName: "CalMag",
|
||||
amountMl: 1,
|
||||
waterLiters: 2,
|
||||
phAfter: 6.4,
|
||||
ecAfter: 1.6,
|
||||
fedAt: daysAgo(5),
|
||||
notes: "Leichte Blattflecken",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,11 @@ export const navigationsData: NavigationType[] = [
|
||||
href: "/stock",
|
||||
iconName: "Package",
|
||||
},
|
||||
{
|
||||
title: "Anbau",
|
||||
href: "/grow",
|
||||
iconName: "Sprout",
|
||||
},
|
||||
{
|
||||
title: "Berichte",
|
||||
href: "/reports",
|
||||
|
||||
Reference in New Issue
Block a user