- ui/checkbox.tsx und form/checkbox-field.tsx: ganze Zeile, Kachel, Aufgabe oder Sheet-Zeile ist der Knopf (Base UI), Haken bzw. Strich für teilweise; role="switch" mit Daumen und Haken. ToggleChip und SwitchRow entfernt. - 14 Kacheln, 11 native Checkboxen, 3 Schalter-Zeilen, 6 Base-UI-Stellen und die Heute-Aufgaben umgestellt; Werte ans Backend unverändert. - Enter in einer Checkbox schickt kein Formular ab und schaltet nicht (Leertaste schaltet); Nachbarn mit mindestens 4 px Abstand; gesperrte Felder mit sichtbarem Grund; gesperrte Kacheln ganz gedimmt. - Baukasten-Wächter: keine eigenen Checkboxen/Schalter, auch bedingte role-Werte und setAttribute; Zeilenlisten mit Abstand. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { fetchHarvests } from "@/lib/harvests/api";
|
|
import { CheckboxField } from "@/components/form/checkbox-field";
|
|
|
|
interface HarvestSelectFieldProps {
|
|
idPrefix: string;
|
|
value: string[];
|
|
onChange: (harvestIds: string[]) => void;
|
|
}
|
|
|
|
/**
|
|
* Picks the harvests an extraction was made from. The set stays editable after
|
|
* the fact: an extraction linked to the wrong harvest breaks the traceability
|
|
* chain from colony to jar, and re-pointing it is the only repair that does
|
|
* not require deleting the extraction and everything downstream of it.
|
|
*/
|
|
export function HarvestSelectField({
|
|
idPrefix,
|
|
value,
|
|
onChange,
|
|
}: HarvestSelectFieldProps) {
|
|
const { data: harvests } = useQuery({
|
|
queryKey: ["harvests"],
|
|
queryFn: () => fetchHarvests(),
|
|
});
|
|
|
|
function toggle(harvestId: string, checked: boolean) {
|
|
onChange(
|
|
checked ? [...value, harvestId] : value.filter((id) => id !== harvestId),
|
|
);
|
|
}
|
|
|
|
const labelId = `${idPrefix}-label`;
|
|
return (
|
|
<div role="group" aria-labelledby={labelId} className="flex flex-col gap-2">
|
|
<span id={labelId} className="text-sm font-medium">
|
|
Ernten
|
|
</span>
|
|
{(harvests ?? []).length === 0 ? (
|
|
<p className="text-sm text-muted-foreground">Keine Ernten erfasst.</p>
|
|
) : null}
|
|
<div className="flex max-h-48 flex-col gap-1 overflow-y-auto">
|
|
{(harvests ?? []).map((harvest) => (
|
|
<CheckboxField
|
|
key={harvest.id}
|
|
id={`${idPrefix}-${harvest.id}`}
|
|
label={[
|
|
new Date(harvest.date).toLocaleDateString("de-DE"),
|
|
harvest.netWeight !== null ? `${harvest.netWeight} kg` : null,
|
|
harvest.colonies.length > 0
|
|
? harvest.colonies.map((entry) => entry.colony.code).join(", ")
|
|
: null,
|
|
]
|
|
.filter(Boolean)
|
|
.join(" · ")}
|
|
checked={value.includes(harvest.id)}
|
|
onCheckedChange={(checked) => toggle(harvest.id, checked)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|