diff --git a/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx b/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx index 3130e82..5f95e5a 100644 --- a/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx +++ b/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx @@ -66,6 +66,7 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { const [loading, setLoading] = useState(!isNew); const [saving, setSaving] = useState(false); + const [saveError, setSaveError] = useState(null); // ─── 初期データ取得 useEffect(() => { @@ -286,9 +287,10 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { // ─── 保存(adjusted 優先、なければ calc 値を使用) const handleSave = async () => { - if (!name.trim()) return alert('計画名を入力してください'); - if (!varietyId) return alert('品種を選択してください'); - if (selectedFields.length === 0) return alert('圃場を1つ以上選択してください'); + setSaveError(null); + if (!name.trim()) { setSaveError('計画名を入力してください'); return; } + if (!varietyId) { setSaveError('品種を選択してください'); return; } + if (selectedFields.length === 0) { setSaveError('圃場を1つ以上選択してください'); return; } const entries: { field_id: number; fertilizer_id: number; bags: number }[] = []; selectedFields.forEach((field) => { @@ -303,8 +305,9 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { }); }); - if (entries.length === 0) { - if (!confirm('袋数が1件も入力されていません。このまま保存しますか?\n(後から編集画面で袋数を入力できます)')) return; + if (entries.length === 0 && planFertilizers.length > 0) { + setSaveError('袋数が1件も入力されていません。計算ボタンを押すか、直接数値を入力してください'); + return; } setSaving(true); @@ -315,12 +318,11 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { } else { await api.put(`/fertilizer/plans/${planId}/`, payload); } - alert('保存しました'); router.push('/fertilizer'); } catch (e: unknown) { const err = e as { response?: { data?: unknown } }; console.error(err); - alert('保存に失敗しました: ' + JSON.stringify(err.response?.data)); + setSaveError('保存に失敗しました: ' + JSON.stringify(err.response?.data)); } finally { setSaving(false); } @@ -390,6 +392,15 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { + {/* エラーバナー */} + {saveError && ( +
+ + {saveError} + +
+ )} + {/* 基本情報 */}
diff --git a/frontend/src/app/fertilizer/masters/page.tsx b/frontend/src/app/fertilizer/masters/page.tsx index a9ef22c..f8e5f78 100644 --- a/frontend/src/app/fertilizer/masters/page.tsx +++ b/frontend/src/app/fertilizer/masters/page.tsx @@ -24,6 +24,7 @@ export default function FertilizerMastersPage() { const [editingId, setEditingId] = useState(null); const [form, setForm] = useState(emptyForm()); const [saving, setSaving] = useState(false); + const [deleteError, setDeleteError] = useState(null); useEffect(() => { fetchFertilizers(); @@ -94,12 +95,13 @@ export default function FertilizerMastersPage() { const handleDelete = async (id: number, name: string) => { if (!confirm(`「${name}」を削除しますか?`)) return; + setDeleteError(null); try { await api.delete(`/fertilizer/fertilizers/${id}/`); await fetchFertilizers(); } catch (e) { console.error(e); - alert('削除に失敗しました(施肥計画で使用中の肥料は削除できません)'); + setDeleteError(`「${name}」の削除に失敗しました(施肥計画で使用中の肥料は削除できません)`); } }; @@ -131,6 +133,14 @@ export default function FertilizerMastersPage() {
+ {deleteError && ( +
+ + {deleteError} + +
+ )} + {loading ? (

読み込み中...

) : (