feat: Schwarmkontrolle-Protokoll
Neues SwarmControlCheck-Modul: strukturierte Weiselzellenkontrollen pro Volk mit Zahl/Verdeckelungsstatus der Zellen, Schwarmstimmung, ergriffener Maßnahme und optionalem naechsten Kontrolltermin. Frontend: neue Karte auf der Volk-Detailseite, Erfassungsformular unter /swarm-control/new sowie Quick-Add-Eintrag.
This commit is contained in:
1 parent
4609a0f9ec
commit
1a7331b6b2
19 files changed
+1076
No files matched your search
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Sprout } from "lucide-react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { fetchColonySwarmControlChecks } from "@/lib/swarm-control/api";
|
||||
import { SWARM_ACTION_LABELS, SWARM_MOOD_LABELS } from "@/lib/swarm-control/labels";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { SwarmControlEditDialog } from "./swarm-control-edit-dialog";
|
||||
|
||||
export function ColonySwarmControlCard({ colonyId }: { colonyId: string }) {
|
||||
const { data: checks, isLoading } = useQuery({
|
||||
queryKey: ["colonies", colonyId, "swarm-control-checks"],
|
||||
queryFn: () => fetchColonySwarmControlChecks(colonyId),
|
||||
});
|
||||
|
||||
return (
|
||||
<Card className="max-w-lg">
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
<CardTitle>Schwarmkontrolle</CardTitle>
|
||||
<Button
|
||||
size="sm"
|
||||
nativeButton={false}
|
||||
render={<Link href={`/swarm-control/new?colonyId=${colonyId}`} />}
|
||||
>
|
||||
Neue Kontrolle
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-3 text-sm">
|
||||
{isLoading ? <p className="text-muted-foreground">Lädt…</p> : null}
|
||||
{!isLoading && (!checks || checks.length === 0) ? (
|
||||
<EmptyState
|
||||
icon={Sprout}
|
||||
title="Noch keine Schwarmkontrolle"
|
||||
description="Erfasse die erste Weiselzellenkontrolle für dieses Volk."
|
||||
/>
|
||||
) : null}
|
||||
{checks?.map((check) => (
|
||||
<div key={check.id} className="rounded-md border p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="font-medium">{new Date(check.date).toLocaleDateString("de-DE")}</p>
|
||||
<SwarmControlEditDialog check={check} />
|
||||
</div>
|
||||
<p className="text-muted-foreground">
|
||||
{check.queenCellsFound !== null
|
||||
? `${check.queenCellsFound} Weiselzelle(n) gefunden`
|
||||
: "Keine Weiselzellen erfasst"}
|
||||
{check.queenCellsCapped ? (
|
||||
<Badge variant="destructive" className="ml-2">
|
||||
Verdeckelt
|
||||
</Badge>
|
||||
) : null}
|
||||
</p>
|
||||
<p>Schwarmstimmung: {SWARM_MOOD_LABELS[check.swarmMood]}</p>
|
||||
{check.actionTaken !== "NONE" ? (
|
||||
<p>Maßnahme: {SWARM_ACTION_LABELS[check.actionTaken]}</p>
|
||||
) : null}
|
||||
{check.nextCheckDate ? (
|
||||
<p>Nächste Kontrolle: {new Date(check.nextCheckDate).toLocaleDateString("de-DE")}</p>
|
||||
) : null}
|
||||
{check.notes ? <p>{check.notes}</p> : null}
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { ColonyActions } from "./colony-actions";
|
||||
import { ColonyHistoryCard } from "./colony-history";
|
||||
import { ColonyInspectionsCard } from "./colony-inspections";
|
||||
import { ColonyVarroaCard } from "./colony-varroa";
|
||||
import { ColonySwarmControlCard } from "./colony-swarm-control";
|
||||
import { ColonyTreatmentsCard } from "./colony-treatments";
|
||||
import { ColonyFeedingsCard } from "./colony-feedings";
|
||||
|
||||
@@ -40,6 +41,7 @@ export default function ColonyDetailPage() {
|
||||
<ColonyActions colony={colony} />
|
||||
<ColonyInspectionsCard colonyId={colony.id} />
|
||||
<ColonyVarroaCard colonyId={colony.id} />
|
||||
<ColonySwarmControlCard colonyId={colony.id} />
|
||||
<ColonyTreatmentsCard colonyId={colony.id} />
|
||||
<ColonyFeedingsCard colonyId={colony.id} />
|
||||
<ColonyHistoryCard colonyId={colony.id} />
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
"use client";
|
||||
|
||||
import { FormEvent, useState } from "react";
|
||||
import { Pencil } from "lucide-react";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { updateSwarmControlCheck } from "@/lib/swarm-control/api";
|
||||
import { SWARM_ACTION_LABELS, SWARM_MOOD_LABELS } from "@/lib/swarm-control/labels";
|
||||
import { SwarmControlAction, SwarmControlCheck, SwarmMood } from "@/lib/swarm-control/types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
export function SwarmControlEditDialog({ check }: { check: SwarmControlCheck }) {
|
||||
const queryClient = useQueryClient();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [date, setDate] = useState(check.date.slice(0, 10));
|
||||
const [queenCellsFound, setQueenCellsFound] = useState(check.queenCellsFound?.toString() ?? "");
|
||||
const [queenCellsCapped, setQueenCellsCapped] = useState(check.queenCellsCapped);
|
||||
const [swarmMood, setSwarmMood] = useState<SwarmMood>(check.swarmMood);
|
||||
const [actionTaken, setActionTaken] = useState<SwarmControlAction>(check.actionTaken);
|
||||
const [nextCheckDate, setNextCheckDate] = useState(check.nextCheckDate?.slice(0, 10) ?? "");
|
||||
const [notes, setNotes] = useState(check.notes ?? "");
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: () =>
|
||||
updateSwarmControlCheck(check.id, {
|
||||
date: new Date(date).toISOString(),
|
||||
queenCellsFound: queenCellsFound ? Number(queenCellsFound) : undefined,
|
||||
queenCellsCapped,
|
||||
swarmMood,
|
||||
actionTaken,
|
||||
nextCheckDate: nextCheckDate ? new Date(nextCheckDate).toISOString() : undefined,
|
||||
notes: notes || undefined,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: ["colonies", check.colonyId, "swarm-control-checks"],
|
||||
});
|
||||
setOpen(false);
|
||||
},
|
||||
});
|
||||
|
||||
function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
mutation.mutate();
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger
|
||||
render={
|
||||
<Button variant="ghost" size="sm">
|
||||
<Pencil className="size-3.5" />
|
||||
Bearbeiten
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Schwarmkontrolle bearbeiten</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-date">Datum</Label>
|
||||
<Input
|
||||
id="swarm-edit-date"
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(event) => setDate(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-cells-found">Weiselzellen gefunden</Label>
|
||||
<Input
|
||||
id="swarm-edit-cells-found"
|
||||
type="number"
|
||||
min={0}
|
||||
value={queenCellsFound}
|
||||
onChange={(event) => setQueenCellsFound(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
className="flex h-9 items-center gap-3 text-sm"
|
||||
htmlFor="swarm-edit-cells-capped"
|
||||
>
|
||||
<input
|
||||
id="swarm-edit-cells-capped"
|
||||
type="checkbox"
|
||||
className="size-4.5"
|
||||
checked={queenCellsCapped}
|
||||
onChange={(event) => setQueenCellsCapped(event.target.checked)}
|
||||
/>
|
||||
Weiselzellen bereits verdeckelt (akut)
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-mood">Schwarmstimmung</Label>
|
||||
<Select
|
||||
value={swarmMood}
|
||||
onValueChange={(value) => setSwarmMood((value ?? swarmMood) as SwarmMood)}
|
||||
>
|
||||
<SelectTrigger id="swarm-edit-mood" className="w-full">
|
||||
<SelectValue>{SWARM_MOOD_LABELS[swarmMood]}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(Object.keys(SWARM_MOOD_LABELS) as SwarmMood[]).map((option) => (
|
||||
<SelectItem key={option} value={option}>
|
||||
{SWARM_MOOD_LABELS[option]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-action">Maßnahme</Label>
|
||||
<Select
|
||||
value={actionTaken}
|
||||
onValueChange={(value) =>
|
||||
setActionTaken((value ?? actionTaken) as SwarmControlAction)
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="swarm-edit-action" className="w-full">
|
||||
<SelectValue>{SWARM_ACTION_LABELS[actionTaken]}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(Object.keys(SWARM_ACTION_LABELS) as SwarmControlAction[]).map((option) => (
|
||||
<SelectItem key={option} value={option}>
|
||||
{SWARM_ACTION_LABELS[option]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-next-check">Nächste Kontrolle</Label>
|
||||
<Input
|
||||
id="swarm-edit-next-check"
|
||||
type="date"
|
||||
value={nextCheckDate}
|
||||
onChange={(event) => setNextCheckDate(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-edit-notes">Notizen</Label>
|
||||
<Textarea
|
||||
id="swarm-edit-notes"
|
||||
value={notes}
|
||||
onChange={(event) => setNotes(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" disabled={mutation.isPending}>
|
||||
{mutation.isPending ? "Speichert…" : "Speichern"}
|
||||
</Button>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
const QUICK_ACTIONS = [
|
||||
{ label: "Durchsicht", href: "/inspections/new" },
|
||||
{ label: "Varroa-Messung", href: "/varroa/new" },
|
||||
{ label: "Schwarmkontrolle", href: "/swarm-control/new" },
|
||||
{ label: "Behandlung", href: "/treatments/new" },
|
||||
{ label: "Fütterung", href: "/feedings/new" },
|
||||
{ label: "Aufgabe", href: "/tasks/new" },
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
"use client";
|
||||
|
||||
import { FormEvent, useState } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import { Sprout } from "lucide-react";
|
||||
import { fetchColonies } from "@/lib/colonies/api";
|
||||
import { createSwarmControlCheck } from "@/lib/swarm-control/api";
|
||||
import { SWARM_ACTION_LABELS, SWARM_MOOD_LABELS } from "@/lib/swarm-control/labels";
|
||||
import { SwarmControlAction, SwarmMood } from "@/lib/swarm-control/types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { PageHeader } from "@/components/page-header";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
|
||||
function todayIsoDate(): string {
|
||||
return new Date().toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
export default function NewSwarmControlCheckPage() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: colonies } = useQuery({
|
||||
queryKey: ["colonies"],
|
||||
queryFn: () => fetchColonies(),
|
||||
});
|
||||
const activeColonies = colonies?.filter((colony) => colony.status === "ACTIVE") ?? [];
|
||||
|
||||
const [colonyId, setColonyId] = useState(searchParams.get("colonyId") ?? "");
|
||||
const [date, setDate] = useState(todayIsoDate());
|
||||
const [queenCellsFound, setQueenCellsFound] = useState("");
|
||||
const [queenCellsCapped, setQueenCellsCapped] = useState(false);
|
||||
const [swarmMood, setSwarmMood] = useState<SwarmMood>("NONE");
|
||||
const [actionTaken, setActionTaken] = useState<SwarmControlAction>("NONE");
|
||||
const [nextCheckDate, setNextCheckDate] = useState("");
|
||||
const [notes, setNotes] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: createSwarmControlCheck,
|
||||
onSuccess: (check) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: ["colonies", check.colonyId, "swarm-control-checks"],
|
||||
});
|
||||
toast.success("Schwarmkontrolle gespeichert");
|
||||
router.push(`/colonies/${check.colonyId}`);
|
||||
},
|
||||
onError: () => {
|
||||
setError("Schwarmkontrolle konnte nicht gespeichert werden.");
|
||||
},
|
||||
});
|
||||
|
||||
function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
if (!colonyId) {
|
||||
setError("Bitte ein Volk auswählen.");
|
||||
return;
|
||||
}
|
||||
mutation.mutate({
|
||||
colonyId,
|
||||
date: new Date(date).toISOString(),
|
||||
queenCellsFound: queenCellsFound ? Number(queenCellsFound) : undefined,
|
||||
queenCellsCapped,
|
||||
swarmMood,
|
||||
actionTaken,
|
||||
nextCheckDate: nextCheckDate ? new Date(nextCheckDate).toISOString() : undefined,
|
||||
notes: notes || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex flex-col gap-4 p-4 sm:p-6">
|
||||
<PageHeader
|
||||
icon={Sprout}
|
||||
title="Neue Schwarmkontrolle"
|
||||
description="Erfasse eine Weiselzellenkontrolle für ein Volk."
|
||||
gradient="var(--gradient-sky)"
|
||||
/>
|
||||
<Card className="max-w-lg">
|
||||
<CardContent>
|
||||
<form className="flex flex-col gap-5" onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-colony">Volk</Label>
|
||||
<Select value={colonyId} onValueChange={(value) => setColonyId(value ?? "")}>
|
||||
<SelectTrigger id="swarm-colony" className="h-11 w-full">
|
||||
<SelectValue placeholder="Volk wählen" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{activeColonies.map((colony) => (
|
||||
<SelectItem key={colony.id} value={colony.id}>
|
||||
{colony.code}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-date">Datum</Label>
|
||||
<Input
|
||||
id="swarm-date"
|
||||
type="date"
|
||||
required
|
||||
className="h-11"
|
||||
value={date}
|
||||
onChange={(event) => setDate(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-cells-found">Weiselzellen gefunden</Label>
|
||||
<Input
|
||||
id="swarm-cells-found"
|
||||
type="number"
|
||||
min={0}
|
||||
inputMode="numeric"
|
||||
className="h-11"
|
||||
value={queenCellsFound}
|
||||
onChange={(event) => setQueenCellsFound(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<label className="flex h-9 items-center gap-3 text-sm" htmlFor="swarm-cells-capped">
|
||||
<input
|
||||
id="swarm-cells-capped"
|
||||
type="checkbox"
|
||||
className="size-4.5"
|
||||
checked={queenCellsCapped}
|
||||
onChange={(event) => setQueenCellsCapped(event.target.checked)}
|
||||
/>
|
||||
Weiselzellen bereits verdeckelt (akut)
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-mood">Schwarmstimmung</Label>
|
||||
<Select
|
||||
value={swarmMood}
|
||||
onValueChange={(value) => setSwarmMood((value ?? swarmMood) as SwarmMood)}
|
||||
>
|
||||
<SelectTrigger id="swarm-mood" className="h-11 w-full">
|
||||
<SelectValue>{SWARM_MOOD_LABELS[swarmMood]}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(Object.keys(SWARM_MOOD_LABELS) as SwarmMood[]).map((option) => (
|
||||
<SelectItem key={option} value={option}>
|
||||
{SWARM_MOOD_LABELS[option]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-action">Maßnahme</Label>
|
||||
<Select
|
||||
value={actionTaken}
|
||||
onValueChange={(value) =>
|
||||
setActionTaken((value ?? actionTaken) as SwarmControlAction)
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="swarm-action" className="h-11 w-full">
|
||||
<SelectValue>{SWARM_ACTION_LABELS[actionTaken]}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(Object.keys(SWARM_ACTION_LABELS) as SwarmControlAction[]).map((option) => (
|
||||
<SelectItem key={option} value={option}>
|
||||
{SWARM_ACTION_LABELS[option]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-next-check">Nächste Kontrolle</Label>
|
||||
<Input
|
||||
id="swarm-next-check"
|
||||
type="date"
|
||||
className="h-11"
|
||||
value={nextCheckDate}
|
||||
onChange={(event) => setNextCheckDate(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="swarm-notes">Notizen</Label>
|
||||
<Textarea
|
||||
id="swarm-notes"
|
||||
value={notes}
|
||||
onChange={(event) => setNotes(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{error ? (
|
||||
<p role="alert" className="text-sm text-destructive">
|
||||
{error}
|
||||
</p>
|
||||
) : null}
|
||||
<Button type="submit" className="h-12 text-base" disabled={mutation.isPending}>
|
||||
{mutation.isPending ? "Wird gespeichert…" : "Kontrolle speichern"}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { apiFetch } from "@/lib/auth/api-client";
|
||||
import {
|
||||
CreateSwarmControlCheckInput,
|
||||
SwarmControlCheck,
|
||||
UpdateSwarmControlCheckInput,
|
||||
} from "./types";
|
||||
|
||||
export function fetchColonySwarmControlChecks(colonyId: string): Promise<SwarmControlCheck[]> {
|
||||
return apiFetch<SwarmControlCheck[]>(`/colonies/${colonyId}/swarm-control-checks`);
|
||||
}
|
||||
|
||||
export function createSwarmControlCheck(
|
||||
input: CreateSwarmControlCheckInput,
|
||||
): Promise<SwarmControlCheck> {
|
||||
return apiFetch<SwarmControlCheck>("/swarm-control-checks", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
|
||||
export function updateSwarmControlCheck(
|
||||
id: string,
|
||||
input: UpdateSwarmControlCheckInput,
|
||||
): Promise<SwarmControlCheck> {
|
||||
return apiFetch<SwarmControlCheck>(`/swarm-control-checks/${id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { SwarmControlAction, SwarmMood } from "./types";
|
||||
|
||||
export const SWARM_MOOD_LABELS: Record<SwarmMood, string> = {
|
||||
NONE: "Keine",
|
||||
LOW: "Gering",
|
||||
HIGH: "Hoch",
|
||||
};
|
||||
|
||||
export const SWARM_ACTION_LABELS: Record<SwarmControlAction, string> = {
|
||||
NONE: "Keine",
|
||||
QUEEN_CELLS_REMOVED: "Weiselzellen gebrochen",
|
||||
ARTIFICIAL_SWARM: "Kunstschwarm gebildet",
|
||||
COLONY_DIVIDED: "Volk geteilt",
|
||||
OTHER: "Sonstiges",
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
export type SwarmMood = "NONE" | "LOW" | "HIGH";
|
||||
export type SwarmControlAction =
|
||||
| "NONE"
|
||||
| "QUEEN_CELLS_REMOVED"
|
||||
| "ARTIFICIAL_SWARM"
|
||||
| "COLONY_DIVIDED"
|
||||
| "OTHER";
|
||||
|
||||
export interface SwarmControlCheck {
|
||||
id: string;
|
||||
colonyId: string;
|
||||
userId: string;
|
||||
date: string;
|
||||
queenCellsFound: number | null;
|
||||
queenCellsCapped: boolean;
|
||||
swarmMood: SwarmMood;
|
||||
actionTaken: SwarmControlAction;
|
||||
notes: string | null;
|
||||
nextCheckDate: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface CreateSwarmControlCheckInput {
|
||||
colonyId: string;
|
||||
date: string;
|
||||
queenCellsFound?: number;
|
||||
queenCellsCapped?: boolean;
|
||||
swarmMood?: SwarmMood;
|
||||
actionTaken?: SwarmControlAction;
|
||||
notes?: string;
|
||||
nextCheckDate?: string;
|
||||
}
|
||||
|
||||
export interface UpdateSwarmControlCheckInput {
|
||||
date?: string;
|
||||
queenCellsFound?: number;
|
||||
queenCellsCapped?: boolean;
|
||||
swarmMood?: SwarmMood;
|
||||
actionTaken?: SwarmControlAction;
|
||||
notes?: string;
|
||||
nextCheckDate?: string;
|
||||
}
|
||||
Reference in new issue
Block a user