- lib/hive: frontend port of the hive domain (ops, validator, facts, layout, follow-ups, describe texts, reason texts) running the backend fixtures, API client - hive card on the colony page (same height as Stammdaten): SVG view, accessible outline tree, frame/part sheets with optimistic save, conflict sheet, history with past states, init from template or another colony, inspection draft mode - follow-up toasts prefilling feeding and treatment forms (treatment end only with an open treatment) - settings page "Beutensysteme" (hive-systems:manage) - NumberStepper decimal steps, reactive motion level hook, holo tokens - spec: owner design decision 2026-10-16 (glass hologram, focus mode) The SVG view is the fallback; the 3D scene follows in L3. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { deriveHiveFacts } from "@/lib/hive/facts";
|
|
import { frames, inlineCatalog, part } from "@/lib/hive/test-utils";
|
|
import type {
|
|
HiveChangeListItem,
|
|
HiveSetupView,
|
|
HiveState,
|
|
HiveSystemDto,
|
|
} from "@/lib/hive/types";
|
|
import type { Colony } from "@/lib/colonies/types";
|
|
|
|
// Shared by the hive card, init and history specs.
|
|
|
|
export const SYSTEM_ID = "sys";
|
|
|
|
export function systemDto(): HiveSystemDto {
|
|
const catalog = inlineCatalog();
|
|
return {
|
|
id: SYSTEM_ID,
|
|
name: "Zander nach Dr. Liebig",
|
|
frameWidthMm: 477,
|
|
frameHeightMm: 220,
|
|
footprintLMm: 525,
|
|
footprintWMm: 430,
|
|
template: {},
|
|
active: true,
|
|
createdAt: "2026-10-01T00:00:00.000Z",
|
|
updatedAt: "2026-10-01T00:00:00.000Z",
|
|
partTypes: [...catalog.partTypes.values()].map((row) => ({
|
|
...row,
|
|
systemId: SYSTEM_ID,
|
|
articleRef: null,
|
|
boxDepth: null,
|
|
createdAt: "2026-10-01T00:00:00.000Z",
|
|
updatedAt: "2026-10-01T00:00:00.000Z",
|
|
})),
|
|
};
|
|
}
|
|
|
|
/** Two boxes with 3 brood frames each, two feeders with 5 l together, a floor insert. */
|
|
export function sampleState(): HiveState {
|
|
return {
|
|
schemaVersion: 1,
|
|
stack: [
|
|
part("f", "floor", { inserts: [part("fi", "floor-insert")] }),
|
|
part("b1", "box", { frames: frames(10).map((frame) => (frame.slot <= 3 ? { ...frame, type: "BROOD" as const } : frame)) }),
|
|
part("b2", "box", { frames: frames(10).map((frame) => (frame.slot <= 3 ? { ...frame, type: "BROOD" as const } : frame)) }),
|
|
part("fe", "feeder", { state: { syrupLiters: 3, fondantKg: 0 } }),
|
|
part("fe2", "feeder", { state: { syrupLiters: 2, fondantKg: 0 } }),
|
|
part("r", "roof"),
|
|
],
|
|
};
|
|
}
|
|
|
|
export function setupView(state: HiveState = sampleState(), colonyId = "colony-1", version = 3): HiveSetupView {
|
|
return {
|
|
colonyId,
|
|
systemId: SYSTEM_ID,
|
|
version,
|
|
state,
|
|
facts: deriveHiveFacts(state, inlineCatalog()),
|
|
updatedAt: "2026-10-12T10:00:00.000Z",
|
|
};
|
|
}
|
|
|
|
export function colonyFixture(extra: Partial<Colony> = {}): Colony {
|
|
return {
|
|
id: "colony-1",
|
|
code: "V-01",
|
|
apiaryId: "apiary-1",
|
|
hiveType: null,
|
|
originText: null,
|
|
colonyType: "PRODUCTION_COLONY",
|
|
status: "ACTIVE",
|
|
strength: null,
|
|
occupiedFrames: null,
|
|
broodStatus: null,
|
|
feedStatus: null,
|
|
healthStatus: null,
|
|
notes: null,
|
|
currentQueenId: null,
|
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
deactivatedAt: null,
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
export function historyItem(extra: Partial<HiveChangeListItem> = {}): HiveChangeListItem {
|
|
return {
|
|
id: "c1",
|
|
version: 3,
|
|
occurredOn: "2026-10-12",
|
|
source: "INSPECTION",
|
|
inspectionId: "i1",
|
|
userId: "u1",
|
|
userName: "Nick",
|
|
ops: [{ op: "setState", id: "fe", key: "syrupLiters", value: 3 }],
|
|
note: null,
|
|
createdAt: "2026-10-12T12:00:00.000Z",
|
|
...extra,
|
|
};
|
|
}
|