Adjust rice transplant plan to store installed box counts

This commit is contained in:
akira
2026-04-05 10:26:14 +09:00
parent 9bcc5e5e21
commit 95c90dd699
6 changed files with 101 additions and 50 deletions

View File

@@ -9,7 +9,7 @@ import { api } from '@/lib/api';
import { Crop, Field, RiceTransplantPlan } from '@/types';
type EntryInput = {
seedling_boxes_per_tan: string;
installed_seedling_boxes: string;
seed_grams_per_box: string;
};
@@ -47,11 +47,17 @@ export default function RiceTransplantEditPage({ planId }: { planId?: number })
return crops.find((crop) => crop.varieties.some((variety) => variety.id === varietyId)) ?? null;
};
const initializeEntry = (fieldId: number, nextDefaultSeedGramsPerBox = defaultSeedGramsPerBox) => {
const calculateDefaultBoxes = (fieldId: number) => {
const field = allFields.find((item) => item.id === fieldId);
const variety = varietyId ? getVariety(varietyId) : null;
const defaultBoxes = variety?.default_seedling_boxes_per_tan ?? '0';
const areaTan = parseFloat(field?.area_tan ?? '0');
const defaultBoxesPerTan = parseFloat(variety?.default_seedling_boxes_per_tan ?? '0');
return (areaTan * defaultBoxesPerTan).toFixed(2);
};
const initializeEntry = (fieldId: number, nextDefaultSeedGramsPerBox = defaultSeedGramsPerBox) => {
return {
seedling_boxes_per_tan: String(defaultBoxes),
installed_seedling_boxes: calculateDefaultBoxes(fieldId),
seed_grams_per_box: nextDefaultSeedGramsPerBox,
};
};
@@ -83,7 +89,7 @@ export default function RiceTransplantEditPage({ planId }: { planId?: number })
setEntries(
plan.entries.reduce((acc: EntryMap, entry) => {
acc[entry.field] = {
seedling_boxes_per_tan: String(entry.seedling_boxes_per_tan),
installed_seedling_boxes: String(entry.installed_seedling_boxes),
seed_grams_per_box: String(entry.seed_grams_per_box),
};
return acc;
@@ -161,14 +167,18 @@ export default function RiceTransplantEditPage({ planId }: { planId?: number })
};
const fieldRows = useMemo(
() => selectedFields.map((field) => ({ field, entry: entries[field.id] ?? initializeEntry(field.id) })),
[selectedFields, entries, varietyId, defaultSeedGramsPerBox]
() =>
selectedFields.map((field) => ({
field,
entry: entries[field.id] ?? initializeEntry(field.id),
defaultBoxes: calculateDefaultBoxes(field.id),
})),
[selectedFields, entries, varietyId, defaultSeedGramsPerBox, allFields]
);
const calculateBoxes = (field: Field, entry: EntryInput) => {
const areaTan = parseFloat(field.area_tan || '0');
const boxesPerTan = parseFloat(entry.seedling_boxes_per_tan || '0');
return areaTan * boxesPerTan;
const calculateBoxes = (_field: Field, entry: EntryInput) => {
const installedBoxes = parseFloat(entry.installed_seedling_boxes || '0');
return installedBoxes;
};
const calculateSeedKg = (field: Field, entry: EntryInput) => {
@@ -205,7 +215,7 @@ export default function RiceTransplantEditPage({ planId }: { planId?: number })
notes,
entries: selectedFields.map((field) => ({
field_id: field.id,
seedling_boxes_per_tan: entries[field.id]?.seedling_boxes_per_tan ?? initializeEntry(field.id).seedling_boxes_per_tan,
installed_seedling_boxes: entries[field.id]?.installed_seedling_boxes ?? initializeEntry(field.id).installed_seedling_boxes,
seed_grams_per_box: entries[field.id]?.seed_grams_per_box ?? defaultSeedGramsPerBox,
})),
};
@@ -407,21 +417,34 @@ export default function RiceTransplantEditPage({ planId }: { planId?: number })
<tr>
<th className="px-4 py-3 text-left font-medium text-gray-700"></th>
<th className="px-4 py-3 text-right font-medium text-gray-700">()</th>
<th className="px-4 py-3 text-right font-medium text-gray-700"></th>
<th className="px-4 py-3 text-right font-medium text-gray-700"></th>
<th className="px-4 py-3 text-right font-medium text-gray-700"></th>
<th className="px-4 py-3 text-right font-medium text-gray-700">g/</th>
<th className="px-4 py-3 text-right font-medium text-gray-700"></th>
<th className="px-4 py-3 text-right font-medium text-gray-700">kg</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
{fieldRows.map(({ field, entry }) => (
{fieldRows.map(({ field, entry, defaultBoxes }) => (
<tr key={field.id} className="hover:bg-gray-50">
<td className="px-4 py-3 font-medium text-gray-900">{field.name}</td>
<td className="px-4 py-3 text-right tabular-nums text-gray-600">{field.area_tan}</td>
<td className="px-4 py-3">
<div className="flex items-center justify-end gap-2">
<span className="text-xs tabular-nums text-gray-500">{defaultBoxes}</span>
<button
type="button"
onClick={() => updateEntry(field.id, 'installed_seedling_boxes', defaultBoxes)}
className="rounded border border-gray-300 px-2 py-1 text-xs text-gray-700 hover:bg-gray-100"
>
</button>
</div>
</td>
<td className="px-4 py-3">
<input
value={entry.seedling_boxes_per_tan}
onChange={(e) => updateEntry(field.id, 'seedling_boxes_per_tan', e.target.value)}
value={entry.installed_seedling_boxes}
onChange={(e) => updateEntry(field.id, 'installed_seedling_boxes', e.target.value)}
className="w-24 rounded-md border border-gray-300 px-2 py-1 text-right focus:outline-none focus:ring-2 focus:ring-green-500"
inputMode="decimal"
/>