Volk Überarbeittung und Englisch Varaiblen ersetzt
This commit is contained in:
1 parent
9282777ac9
commit
8520678a48
11 files changed
+208
-81
No files matched your search
@@ -209,6 +209,15 @@ enum ColonyStatus {
|
|||||||
MERGED
|
MERGED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fuenfstufige Zustandsskala, geteilt von Brut-, Futter- und Gesundheitsstatus.
|
||||||
|
enum ColonyCondition {
|
||||||
|
EXCELLENT
|
||||||
|
GOOD
|
||||||
|
AVERAGE
|
||||||
|
WEAK
|
||||||
|
CRITICAL
|
||||||
|
}
|
||||||
|
|
||||||
model Colony {
|
model Colony {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
code String @unique
|
code String @unique
|
||||||
@@ -219,9 +228,9 @@ model Colony {
|
|||||||
colonyType ColonyType
|
colonyType ColonyType
|
||||||
status ColonyStatus @default(ACTIVE)
|
status ColonyStatus @default(ACTIVE)
|
||||||
strength Int?
|
strength Int?
|
||||||
broodStatus String?
|
broodStatus ColonyCondition?
|
||||||
feedStatus String?
|
feedStatus ColonyCondition?
|
||||||
healthStatus String?
|
healthStatus ColonyCondition?
|
||||||
notes String?
|
notes String?
|
||||||
currentQueenId String? @unique
|
currentQueenId String? @unique
|
||||||
currentQueen Queen? @relation("ColonyCurrentQueen", fields: [currentQueenId], references: [id])
|
currentQueen Queen? @relation("ColonyCurrentQueen", fields: [currentQueenId], references: [id])
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { IsEnum, IsInt, IsOptional, IsString } from 'class-validator';
|
import { IsEnum, IsInt, IsOptional, IsString, Max, Min } from 'class-validator';
|
||||||
import { ColonyType } from '../../../generated/prisma';
|
import { ColonyCondition, ColonyType } from '../../../generated/prisma';
|
||||||
|
|
||||||
export class CreateColonyDto {
|
export class CreateColonyDto {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@@ -25,25 +25,27 @@ export class CreateColonyDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
originText?: string;
|
originText?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional({ minimum: 1, maximum: 10 })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
@Min(1)
|
||||||
|
@Max(10)
|
||||||
strength?: number;
|
strength?: number;
|
||||||
|
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional({ enum: ColonyCondition })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsEnum(ColonyCondition)
|
||||||
broodStatus?: string;
|
broodStatus?: ColonyCondition;
|
||||||
|
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional({ enum: ColonyCondition })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsEnum(ColonyCondition)
|
||||||
feedStatus?: string;
|
feedStatus?: ColonyCondition;
|
||||||
|
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional({ enum: ColonyCondition })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsEnum(ColonyCondition)
|
||||||
healthStatus?: string;
|
healthStatus?: ColonyCondition;
|
||||||
|
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -7,5 +7,6 @@
|
|||||||
"maxWorkers": 4,
|
"maxWorkers": 4,
|
||||||
"transform": {
|
"transform": {
|
||||||
"^.+\\.(t|j)s$": "ts-jest"
|
"^.+\\.(t|j)s$": "ts-jest"
|
||||||
}
|
},
|
||||||
|
"transformIgnorePatterns": ["node_modules/(?!(otplib|@otplib|@scure|@noble)/)"]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE_NAME = "apicore-shell-v1";
|
const CACHE_NAME = "apicore-shell-v2";
|
||||||
|
|
||||||
self.addEventListener("install", () => {
|
self.addEventListener("install", () => {
|
||||||
self.skipWaiting();
|
self.skipWaiting();
|
||||||
@@ -27,12 +27,22 @@ self.addEventListener("fetch", (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Page navigations must never be answered with a synthetic Response.error() -
|
||||||
|
// Chrome/Edge render that as a native "This page couldn't load" interstitial
|
||||||
|
// instead of the app. Let the browser handle navigations directly; only
|
||||||
|
// static assets (JS/CSS/images) go through the offline-cache fallback below.
|
||||||
|
if (request.mode === "navigate") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
fetch(request)
|
fetch(request)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const responseClone = response.clone();
|
const responseClone = response.clone();
|
||||||
caches.open(CACHE_NAME).then((cache) => cache.put(request, responseClone));
|
return caches
|
||||||
return response;
|
.open(CACHE_NAME)
|
||||||
|
.then((cache) => cache.put(request, responseClone))
|
||||||
|
.then(() => response);
|
||||||
})
|
})
|
||||||
.catch(() => caches.match(request).then((cached) => cached || Response.error())),
|
.catch(() => caches.match(request).then((cached) => cached || Response.error())),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
splitColony,
|
splitColony,
|
||||||
} from "@/lib/colonies/api";
|
} from "@/lib/colonies/api";
|
||||||
import { Colony, ColonyType } from "@/lib/colonies/types";
|
import { Colony, ColonyType } from "@/lib/colonies/types";
|
||||||
|
import { COLONY_TYPES, COLONY_TYPE_LABELS } from "@/lib/colonies/labels";
|
||||||
import { fetchApiaries } from "@/lib/apiaries/api";
|
import { fetchApiaries } from "@/lib/apiaries/api";
|
||||||
import { fetchColonies } from "@/lib/colonies/api";
|
import { fetchColonies } from "@/lib/colonies/api";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -33,15 +34,6 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
const COLONY_TYPES: ColonyType[] = [
|
|
||||||
"PRODUCTION_COLONY",
|
|
||||||
"NUCLEUS_COLONY",
|
|
||||||
"YOUNG_COLONY",
|
|
||||||
"CARETAKER_COLONY",
|
|
||||||
"MATING_NUCLEUS",
|
|
||||||
"RESERVE_COLONY",
|
|
||||||
];
|
|
||||||
|
|
||||||
function invalidateColony(
|
function invalidateColony(
|
||||||
queryClient: ReturnType<typeof useQueryClient>,
|
queryClient: ReturnType<typeof useQueryClient>,
|
||||||
colonyId: string,
|
colonyId: string,
|
||||||
@@ -169,7 +161,7 @@ function SplitDialog({ colony }: { colony: Colony }) {
|
|||||||
<SelectContent>
|
<SelectContent>
|
||||||
{COLONY_TYPES.map((type) => (
|
{COLONY_TYPES.map((type) => (
|
||||||
<SelectItem key={type} value={type}>
|
<SelectItem key={type} value={type}>
|
||||||
{type}
|
{COLONY_TYPE_LABELS[type]}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -4,13 +4,28 @@ import { FormEvent, useState } from "react";
|
|||||||
import { Layers } from "lucide-react";
|
import { Layers } from "lucide-react";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { updateColony } from "@/lib/colonies/api";
|
import { updateColony } from "@/lib/colonies/api";
|
||||||
import { Colony } from "@/lib/colonies/types";
|
import { Colony, ColonyCondition, ColonyType } from "@/lib/colonies/types";
|
||||||
|
import {
|
||||||
|
COLONY_CONDITIONS,
|
||||||
|
COLONY_CONDITION_LABELS,
|
||||||
|
COLONY_CONDITION_TONE_CLASS,
|
||||||
|
COLONY_STATUS_LABELS,
|
||||||
|
COLONY_STRENGTH_OPTIONS,
|
||||||
|
COLONY_TYPES,
|
||||||
|
COLONY_TYPE_LABELS,
|
||||||
|
} from "@/lib/colonies/labels";
|
||||||
import { statusTone } from "@/lib/status-tone";
|
import { statusTone } from "@/lib/status-tone";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -18,21 +33,67 @@ import {
|
|||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
|
|
||||||
|
function ConditionSelect({
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
value: ColonyCondition | undefined;
|
||||||
|
onChange: (value: ColonyCondition) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Label htmlFor={id}>{label}</Label>
|
||||||
|
<Select value={value} onValueChange={(next) => onChange(next as ColonyCondition)}>
|
||||||
|
<SelectTrigger id={id}>
|
||||||
|
<SelectValue placeholder="Nicht erfasst">
|
||||||
|
{value ? (
|
||||||
|
<Badge className={COLONY_CONDITION_TONE_CLASS[value]}>
|
||||||
|
{COLONY_CONDITION_LABELS[value]}
|
||||||
|
</Badge>
|
||||||
|
) : undefined}
|
||||||
|
</SelectValue>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{COLONY_CONDITIONS.map((condition) => (
|
||||||
|
<SelectItem key={condition} value={condition}>
|
||||||
|
<Badge className={COLONY_CONDITION_TONE_CLASS[condition]}>
|
||||||
|
{COLONY_CONDITION_LABELS[condition]}
|
||||||
|
</Badge>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function ColonyEditCard({ colony }: { colony: Colony }) {
|
export function ColonyEditCard({ colony }: { colony: Colony }) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const [colonyType, setColonyType] = useState<ColonyType>(colony.colonyType);
|
||||||
const [strength, setStrength] = useState(colony.strength?.toString() ?? "");
|
const [strength, setStrength] = useState(colony.strength?.toString() ?? "");
|
||||||
const [broodStatus, setBroodStatus] = useState(colony.broodStatus ?? "");
|
const [broodStatus, setBroodStatus] = useState<ColonyCondition | undefined>(
|
||||||
const [feedStatus, setFeedStatus] = useState(colony.feedStatus ?? "");
|
colony.broodStatus ?? undefined,
|
||||||
const [healthStatus, setHealthStatus] = useState(colony.healthStatus ?? "");
|
);
|
||||||
|
const [feedStatus, setFeedStatus] = useState<ColonyCondition | undefined>(
|
||||||
|
colony.feedStatus ?? undefined,
|
||||||
|
);
|
||||||
|
const [healthStatus, setHealthStatus] = useState<ColonyCondition | undefined>(
|
||||||
|
colony.healthStatus ?? undefined,
|
||||||
|
);
|
||||||
const [notes, setNotes] = useState(colony.notes ?? "");
|
const [notes, setNotes] = useState(colony.notes ?? "");
|
||||||
|
|
||||||
const updateMutation = useMutation({
|
const updateMutation = useMutation({
|
||||||
mutationFn: () =>
|
mutationFn: () =>
|
||||||
updateColony(colony.id, {
|
updateColony(colony.id, {
|
||||||
|
colonyType,
|
||||||
strength: strength ? Number(strength) : undefined,
|
strength: strength ? Number(strength) : undefined,
|
||||||
broodStatus: broodStatus || undefined,
|
broodStatus,
|
||||||
feedStatus: feedStatus || undefined,
|
feedStatus,
|
||||||
healthStatus: healthStatus || undefined,
|
healthStatus,
|
||||||
notes: notes || undefined,
|
notes: notes || undefined,
|
||||||
}),
|
}),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -58,43 +119,61 @@ export function ColonyEditCard({ colony }: { colony: Colony }) {
|
|||||||
</span>
|
</span>
|
||||||
<CardTitle className="font-mono">{colony.code}</CardTitle>
|
<CardTitle className="font-mono">{colony.code}</CardTitle>
|
||||||
</div>
|
</div>
|
||||||
<Badge variant={statusTone(colony.status)}>{colony.status}</Badge>
|
<Badge variant={statusTone(colony.status)}>{COLONY_STATUS_LABELS[colony.status]}</Badge>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
|
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Label htmlFor="colony-type">Volktyp</Label>
|
||||||
|
<Select
|
||||||
|
value={colonyType}
|
||||||
|
onValueChange={(value) => setColonyType(value as ColonyType)}
|
||||||
|
>
|
||||||
|
<SelectTrigger id="colony-type">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{COLONY_TYPES.map((type) => (
|
||||||
|
<SelectItem key={type} value={type}>
|
||||||
|
{COLONY_TYPE_LABELS[type]}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<Label htmlFor="colony-strength">Volksstärke</Label>
|
<Label htmlFor="colony-strength">Volksstärke</Label>
|
||||||
<Input
|
<Select value={strength} onValueChange={(value) => setStrength(value ?? "")}>
|
||||||
id="colony-strength"
|
<SelectTrigger id="colony-strength">
|
||||||
type="number"
|
<SelectValue placeholder="Nicht erfasst" />
|
||||||
value={strength}
|
</SelectTrigger>
|
||||||
onChange={(event) => setStrength(event.target.value)}
|
<SelectContent>
|
||||||
/>
|
{COLONY_STRENGTH_OPTIONS.map((option) => (
|
||||||
|
<SelectItem key={option} value={option.toString()}>
|
||||||
|
{option}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<ConditionSelect
|
||||||
<Label htmlFor="colony-brood">Brutstatus</Label>
|
|
||||||
<Input
|
|
||||||
id="colony-brood"
|
id="colony-brood"
|
||||||
|
label="Brutstatus"
|
||||||
value={broodStatus}
|
value={broodStatus}
|
||||||
onChange={(event) => setBroodStatus(event.target.value)}
|
onChange={setBroodStatus}
|
||||||
/>
|
/>
|
||||||
</div>
|
<ConditionSelect
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<Label htmlFor="colony-feed">Futterstatus</Label>
|
|
||||||
<Input
|
|
||||||
id="colony-feed"
|
id="colony-feed"
|
||||||
|
label="Futterstatus"
|
||||||
value={feedStatus}
|
value={feedStatus}
|
||||||
onChange={(event) => setFeedStatus(event.target.value)}
|
onChange={setFeedStatus}
|
||||||
/>
|
/>
|
||||||
</div>
|
<ConditionSelect
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
<Label htmlFor="colony-health">Gesundheitsstatus</Label>
|
|
||||||
<Input
|
|
||||||
id="colony-health"
|
id="colony-health"
|
||||||
|
label="Gesundheitsstatus"
|
||||||
value={healthStatus}
|
value={healthStatus}
|
||||||
onChange={(event) => setHealthStatus(event.target.value)}
|
onChange={setHealthStatus}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<Label htmlFor="colony-notes">Notizen</Label>
|
<Label htmlFor="colony-notes">Notizen</Label>
|
||||||
<Textarea
|
<Textarea
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { createColony } from "@/lib/colonies/api";
|
import { createColony } from "@/lib/colonies/api";
|
||||||
import { ColonyType } from "@/lib/colonies/types";
|
import { ColonyType } from "@/lib/colonies/types";
|
||||||
|
import { COLONY_TYPES, COLONY_TYPE_LABELS } from "@/lib/colonies/labels";
|
||||||
import { Layers } from "lucide-react";
|
import { Layers } from "lucide-react";
|
||||||
import { fetchApiaries } from "@/lib/apiaries/api";
|
import { fetchApiaries } from "@/lib/apiaries/api";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -20,15 +21,6 @@ import {
|
|||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
|
||||||
const COLONY_TYPES: ColonyType[] = [
|
|
||||||
"PRODUCTION_COLONY",
|
|
||||||
"NUCLEUS_COLONY",
|
|
||||||
"YOUNG_COLONY",
|
|
||||||
"CARETAKER_COLONY",
|
|
||||||
"MATING_NUCLEUS",
|
|
||||||
"RESERVE_COLONY",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function NewColonyPage() {
|
export default function NewColonyPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -106,7 +98,7 @@ export default function NewColonyPage() {
|
|||||||
<SelectContent>
|
<SelectContent>
|
||||||
{COLONY_TYPES.map((type) => (
|
{COLONY_TYPES.map((type) => (
|
||||||
<SelectItem key={type} value={type}>
|
<SelectItem key={type} value={type}>
|
||||||
{type}
|
{COLONY_TYPE_LABELS[type]}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|||||||
@@ -44,6 +44,6 @@ describe("ColoniesPage", () => {
|
|||||||
renderWithClient(<ColoniesPage />);
|
renderWithClient(<ColoniesPage />);
|
||||||
|
|
||||||
expect(await screen.findByText("V-001")).toBeInTheDocument();
|
expect(await screen.findByText("V-001")).toBeInTheDocument();
|
||||||
expect(screen.getByText("PRODUCTION_COLONY")).toBeInTheDocument();
|
expect(screen.getByText("Wirtschaftsvolk")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -6,6 +6,7 @@ import { Layers } from "lucide-react";
|
|||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { fetchColonies } from "@/lib/colonies/api";
|
import { fetchColonies } from "@/lib/colonies/api";
|
||||||
import { ColonyStatus } from "@/lib/colonies/types";
|
import { ColonyStatus } from "@/lib/colonies/types";
|
||||||
|
import { COLONY_CONDITION_LABELS, COLONY_STATUS_LABELS, COLONY_TYPE_LABELS } from "@/lib/colonies/labels";
|
||||||
import { exportColoniesCsv } from "@/lib/export/api";
|
import { exportColoniesCsv } from "@/lib/export/api";
|
||||||
import { statusTone } from "@/lib/status-tone";
|
import { statusTone } from "@/lib/status-tone";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -79,13 +80,15 @@ export default function ColoniesPage() {
|
|||||||
onValueChange={(value) => setStatus(value === "ALL" ? "" : ((value ?? "") as ColonyStatus))}
|
onValueChange={(value) => setStatus(value === "ALL" ? "" : ((value ?? "") as ColonyStatus))}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-40">
|
<SelectTrigger className="w-40">
|
||||||
<SelectValue placeholder="Status">{status || "Alle Status"}</SelectValue>
|
<SelectValue placeholder="Status">
|
||||||
|
{status ? COLONY_STATUS_LABELS[status] : "Alle Status"}
|
||||||
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="ALL">Alle Status</SelectItem>
|
<SelectItem value="ALL">Alle Status</SelectItem>
|
||||||
{statusOptions.map((option) => (
|
{statusOptions.map((option) => (
|
||||||
<SelectItem key={option} value={option}>
|
<SelectItem key={option} value={option}>
|
||||||
{option}
|
{COLONY_STATUS_LABELS[option]}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
@@ -119,11 +122,18 @@ export default function ColoniesPage() {
|
|||||||
href={`/colonies/${colony.id}`}
|
href={`/colonies/${colony.id}`}
|
||||||
icon={Layers}
|
icon={Layers}
|
||||||
title={<span className="font-mono">{colony.code}</span>}
|
title={<span className="font-mono">{colony.code}</span>}
|
||||||
subtitle={colony.colonyType}
|
subtitle={COLONY_TYPE_LABELS[colony.colonyType]}
|
||||||
badge={<Badge variant={statusTone(colony.status)}>{colony.status}</Badge>}
|
badge={
|
||||||
|
<Badge variant={statusTone(colony.status)}>
|
||||||
|
{COLONY_STATUS_LABELS[colony.status]}
|
||||||
|
</Badge>
|
||||||
|
}
|
||||||
fields={[
|
fields={[
|
||||||
{ label: "Stärke", value: colony.strength ?? "—" },
|
{ label: "Stärke", value: colony.strength ?? "—" },
|
||||||
{ label: "Gesundheit", value: colony.healthStatus ?? "—" },
|
{
|
||||||
|
label: "Gesundheit",
|
||||||
|
value: colony.healthStatus ? COLONY_CONDITION_LABELS[colony.healthStatus] : "—",
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -31,6 +31,16 @@
|
|||||||
--color-warning-foreground: var(--warning-foreground);
|
--color-warning-foreground: var(--warning-foreground);
|
||||||
--color-success: var(--success);
|
--color-success: var(--success);
|
||||||
--color-success-foreground: var(--success-foreground);
|
--color-success-foreground: var(--success-foreground);
|
||||||
|
--color-condition-excellent: var(--condition-excellent);
|
||||||
|
--color-condition-excellent-foreground: var(--condition-excellent-foreground);
|
||||||
|
--color-condition-good: var(--condition-good);
|
||||||
|
--color-condition-good-foreground: var(--condition-good-foreground);
|
||||||
|
--color-condition-average: var(--condition-average);
|
||||||
|
--color-condition-average-foreground: var(--condition-average-foreground);
|
||||||
|
--color-condition-weak: var(--condition-weak);
|
||||||
|
--color-condition-weak-foreground: var(--condition-weak-foreground);
|
||||||
|
--color-condition-critical: var(--condition-critical);
|
||||||
|
--color-condition-critical-foreground: var(--condition-critical-foreground);
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
@@ -87,6 +97,16 @@
|
|||||||
--warning-foreground: oklch(0.24 0.04 60);
|
--warning-foreground: oklch(0.24 0.04 60);
|
||||||
--success: oklch(0.46 0.06 145);
|
--success: oklch(0.46 0.06 145);
|
||||||
--success-foreground: oklch(0.98 0.015 100);
|
--success-foreground: oklch(0.98 0.015 100);
|
||||||
|
--condition-excellent: oklch(0.58 0.13 145);
|
||||||
|
--condition-excellent-foreground: oklch(0.24 0.05 145);
|
||||||
|
--condition-good: oklch(0.64 0.13 118);
|
||||||
|
--condition-good-foreground: oklch(0.26 0.05 118);
|
||||||
|
--condition-average: oklch(0.7 0.14 90);
|
||||||
|
--condition-average-foreground: oklch(0.28 0.05 90);
|
||||||
|
--condition-weak: oklch(0.68 0.15 55);
|
||||||
|
--condition-weak-foreground: oklch(0.26 0.05 55);
|
||||||
|
--condition-critical: oklch(0.55 0.16 30);
|
||||||
|
--condition-critical-foreground: oklch(0.24 0.05 30);
|
||||||
--chart-1: oklch(0.6 0.135 50);
|
--chart-1: oklch(0.6 0.135 50);
|
||||||
--chart-2: oklch(0.46 0.06 145);
|
--chart-2: oklch(0.46 0.06 145);
|
||||||
--chart-3: oklch(0.68 0.14 75);
|
--chart-3: oklch(0.68 0.14 75);
|
||||||
@@ -131,6 +151,16 @@
|
|||||||
--warning-foreground: oklch(0.2 0.03 60);
|
--warning-foreground: oklch(0.2 0.03 60);
|
||||||
--success: oklch(0.62 0.075 145);
|
--success: oklch(0.62 0.075 145);
|
||||||
--success-foreground: oklch(0.15 0.02 145);
|
--success-foreground: oklch(0.15 0.02 145);
|
||||||
|
--condition-excellent: oklch(0.66 0.11 145);
|
||||||
|
--condition-excellent-foreground: oklch(0.2 0.04 145);
|
||||||
|
--condition-good: oklch(0.72 0.12 118);
|
||||||
|
--condition-good-foreground: oklch(0.22 0.04 118);
|
||||||
|
--condition-average: oklch(0.76 0.13 90);
|
||||||
|
--condition-average-foreground: oklch(0.24 0.04 90);
|
||||||
|
--condition-weak: oklch(0.74 0.13 55);
|
||||||
|
--condition-weak-foreground: oklch(0.22 0.04 55);
|
||||||
|
--condition-critical: oklch(0.62 0.16 30);
|
||||||
|
--condition-critical-foreground: oklch(0.2 0.04 30);
|
||||||
--chart-1: oklch(0.72 0.13 55);
|
--chart-1: oklch(0.72 0.13 55);
|
||||||
--chart-2: oklch(0.62 0.075 145);
|
--chart-2: oklch(0.62 0.075 145);
|
||||||
--chart-3: oklch(0.74 0.13 75);
|
--chart-3: oklch(0.74 0.13 75);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export type ColonyStatus =
|
|||||||
| "DECEASED"
|
| "DECEASED"
|
||||||
| "MERGED";
|
| "MERGED";
|
||||||
|
|
||||||
|
export type ColonyCondition = "EXCELLENT" | "GOOD" | "AVERAGE" | "WEAK" | "CRITICAL";
|
||||||
|
|
||||||
export interface Colony {
|
export interface Colony {
|
||||||
id: string;
|
id: string;
|
||||||
code: string;
|
code: string;
|
||||||
@@ -25,9 +27,9 @@ export interface Colony {
|
|||||||
colonyType: ColonyType;
|
colonyType: ColonyType;
|
||||||
status: ColonyStatus;
|
status: ColonyStatus;
|
||||||
strength: number | null;
|
strength: number | null;
|
||||||
broodStatus: string | null;
|
broodStatus: ColonyCondition | null;
|
||||||
feedStatus: string | null;
|
feedStatus: ColonyCondition | null;
|
||||||
healthStatus: string | null;
|
healthStatus: ColonyCondition | null;
|
||||||
notes: string | null;
|
notes: string | null;
|
||||||
currentQueenId: string | null;
|
currentQueenId: string | null;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
@@ -49,9 +51,9 @@ export interface UpdateColonyInput {
|
|||||||
originText?: string;
|
originText?: string;
|
||||||
colonyType?: ColonyType;
|
colonyType?: ColonyType;
|
||||||
strength?: number;
|
strength?: number;
|
||||||
broodStatus?: string;
|
broodStatus?: ColonyCondition;
|
||||||
feedStatus?: string;
|
feedStatus?: ColonyCondition;
|
||||||
healthStatus?: string;
|
healthStatus?: ColonyCondition;
|
||||||
notes?: string;
|
notes?: string;
|
||||||
status?: ColonyStatus;
|
status?: ColonyStatus;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user