- In-app reminders: task due (skips rescheduled tasks, catch-up wording) and a per-user morning digest step in the daily job - Frontend: "Als Nächstes" on the colony page, "Heute" on the dashboard, inspection-due card, season chip, apiary overview fields, cleanup sheet for ended colonies - Frontend: plausibility warnings that stay until dismissed, withdrawal spans in the calendar, notification bell with categories and links, notification settings in the profile - ARCHITECTURE.md: T4a sections 11.1-11.10, assumptions 31-41, handler table and daily job step order Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
157 lines
3.9 KiB
TypeScript
157 lines
3.9 KiB
TypeScript
// Test data for offline packs - shared by the specs, never imported by app code.
|
|
import type { StoredPack } from "@/lib/offline/db";
|
|
import type { ColonyOverviewRow, OfflinePackV1 } from "./field-types";
|
|
|
|
export const MINUTE_MS = 60 * 1000;
|
|
export const HOUR_MS = 60 * MINUTE_MS;
|
|
export const DAY_MS = 24 * HOUR_MS;
|
|
|
|
type PackColony = OfflinePackV1["colonies"][number];
|
|
type PackInspection = NonNullable<OfflinePackV1["inspections"]>[number];
|
|
type PackTask = NonNullable<OfflinePackV1["tasks"]>[number];
|
|
type PackQueen = NonNullable<OfflinePackV1["queens"]>[number];
|
|
|
|
export function packColony(id: string, code: string, overrides: Partial<PackColony> = {}): PackColony {
|
|
return {
|
|
id,
|
|
code,
|
|
apiaryId: "apiary-1",
|
|
status: "ACTIVE",
|
|
colonyType: "PRODUCTION_COLONY",
|
|
hiveType: "Zander",
|
|
strength: 8,
|
|
occupiedFrames: 9,
|
|
broodStatus: "GOOD",
|
|
feedStatus: "GOOD",
|
|
healthStatus: "GOOD",
|
|
currentQueenId: null,
|
|
notes: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
export function overviewRow(colony: PackColony, overrides: Partial<ColonyOverviewRow> = {}): ColonyOverviewRow {
|
|
return {
|
|
id: colony.id,
|
|
code: colony.code,
|
|
status: colony.status,
|
|
strength: colony.strength,
|
|
occupiedFrames: colony.occupiedFrames,
|
|
broodStatus: colony.broodStatus,
|
|
feedStatus: colony.feedStatus,
|
|
healthStatus: colony.healthStatus,
|
|
lastInspectionDate: new Date().toISOString(),
|
|
inspectionDueOn: null,
|
|
segment: null,
|
|
nextStepTitle: null,
|
|
openWarnings: 0,
|
|
openCritical: 0,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
export function packInspection(
|
|
id: string,
|
|
colonyId: string,
|
|
date: string,
|
|
overrides: Partial<PackInspection> = {},
|
|
): PackInspection {
|
|
return {
|
|
id,
|
|
colonyId,
|
|
date,
|
|
weather: null,
|
|
temperature: null,
|
|
colonyStrength: null,
|
|
broodAmount: null,
|
|
broodFrames: null,
|
|
broodPattern: null,
|
|
openBroodPresent: null,
|
|
cappedBroodPresent: null,
|
|
eggsPresent: null,
|
|
queenSeen: null,
|
|
queenCellsPresent: null,
|
|
swarmMood: null,
|
|
gentleness: null,
|
|
combBehavior: null,
|
|
feedStatus: null,
|
|
honeySuperStatus: null,
|
|
healthIssues: null,
|
|
varroaIssues: null,
|
|
measures: null,
|
|
notes: null,
|
|
createdAt: date,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
export function packTask(id: string, title: string, overrides: Partial<PackTask> = {}): PackTask {
|
|
return {
|
|
id,
|
|
title,
|
|
description: null,
|
|
dueDate: null,
|
|
priority: "NORMAL",
|
|
status: "OPEN",
|
|
relatedType: "COLONY",
|
|
relatedId: null,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
export function packQueen(id: string, code: string, overrides: Partial<PackQueen> = {}): PackQueen {
|
|
return {
|
|
id,
|
|
code,
|
|
hatchYear: 2025,
|
|
breed: "Carnica",
|
|
markingColor: "Rot",
|
|
markingNumber: "12",
|
|
status: "ACTIVE",
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
interface PackOptions {
|
|
apiaryId?: string;
|
|
apiaryName?: string;
|
|
colonies?: PackColony[];
|
|
queens?: OfflinePackV1["queens"];
|
|
inspections?: OfflinePackV1["inspections"];
|
|
tasks?: OfflinePackV1["tasks"];
|
|
inspectionsVisible?: boolean;
|
|
}
|
|
|
|
/** A pack as the server sends it: colonies, their overview rows and the sections. */
|
|
export function offlinePack({
|
|
apiaryId = "apiary-1",
|
|
apiaryName = "Obstwiese",
|
|
colonies = [packColony("colony-1", "A1", { apiaryId })],
|
|
queens = [],
|
|
inspections = [],
|
|
tasks = [],
|
|
inspectionsVisible = true,
|
|
}: PackOptions = {}): OfflinePackV1 {
|
|
return {
|
|
version: 1,
|
|
generatedAt: "2026-10-13T08:00:00.000Z",
|
|
apiary: { id: apiaryId, name: apiaryName, location: "Hinterm Hof", status: "ACTIVE" },
|
|
overview: {
|
|
apiaryId,
|
|
inspectionsVisible,
|
|
rows: colonies.map((colony) => overviewRow(colony)),
|
|
},
|
|
colonies,
|
|
queens,
|
|
inspections,
|
|
tasks,
|
|
};
|
|
}
|
|
|
|
export function storedPack(
|
|
pack: OfflinePackV1,
|
|
{ ownerUserId = "user-1", savedAt = new Date().toISOString() } = {},
|
|
): StoredPack {
|
|
return { apiaryId: pack.apiary.id, ownerUserId, savedAt, pack };
|
|
}
|