施肥機能の confirm() をすべて除去しエラーバナー化

ブラウザが confirm() をブロックすると何も起きず原因不明になる問題を修正。
confirm() を除去し、失敗時はインラインエラーバナーで理由を表示する。
- masters: 肥料削除失敗 → バナー表示
- page: 計画削除失敗 → バナー表示
- FertilizerEditPage: 肥料除去はローカル操作のため confirm だけ除去

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Akira
2026-03-01 17:16:08 +09:00
parent db20a9c3d2
commit 84ae939d73
3 changed files with 11 additions and 4 deletions

View File

@@ -143,7 +143,6 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) {
}; };
const removeFertilizer = (id: number) => { const removeFertilizer = (id: number) => {
if (!confirm('この肥料を計画から削除しますか?')) return;
setPlanFertilizers((prev) => prev.filter((f) => f.id !== id)); setPlanFertilizers((prev) => prev.filter((f) => f.id !== id));
setCalcSettings((prev) => prev.filter((s) => s.fertilizer_id !== id)); setCalcSettings((prev) => prev.filter((s) => s.fertilizer_id !== id));
const dropCol = (m: Matrix): Matrix => { const dropCol = (m: Matrix): Matrix => {

View File

@@ -94,7 +94,6 @@ export default function FertilizerMastersPage() {
}; };
const handleDelete = async (id: number, name: string) => { const handleDelete = async (id: number, name: string) => {
if (!confirm(`${name}」を削除しますか?`)) return;
setDeleteError(null); setDeleteError(null);
try { try {
await api.delete(`/fertilizer/fertilizers/${id}/`); await api.delete(`/fertilizer/fertilizers/${id}/`);

View File

@@ -20,6 +20,7 @@ export default function FertilizerPage() {
}); });
const [plans, setPlans] = useState<FertilizationPlan[]>([]); const [plans, setPlans] = useState<FertilizationPlan[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [deleteError, setDeleteError] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
localStorage.setItem('fertilizerYear', String(year)); localStorage.setItem('fertilizerYear', String(year));
@@ -39,13 +40,13 @@ export default function FertilizerPage() {
}; };
const handleDelete = async (id: number, name: string) => { const handleDelete = async (id: number, name: string) => {
if (!confirm(`${name}」を削除しますか?`)) return; setDeleteError(null);
try { try {
await api.delete(`/fertilizer/plans/${id}/`); await api.delete(`/fertilizer/plans/${id}/`);
await fetchPlans(); await fetchPlans();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
alert('削除に失敗しました'); setDeleteError(`${name}」の削除に失敗しました`);
} }
}; };
@@ -106,6 +107,14 @@ export default function FertilizerPage() {
</select> </select>
</div> </div>
{deleteError && (
<div className="mb-4 flex items-start gap-2 bg-red-50 border border-red-300 text-red-700 rounded-lg px-4 py-3 text-sm">
<span className="font-bold shrink-0"></span>
<span>{deleteError}</span>
<button onClick={() => setDeleteError(null)} className="ml-auto shrink-0 text-red-400 hover:text-red-600"></button>
</div>
)}
{loading ? ( {loading ? (
<p className="text-gray-500">...</p> <p className="text-gray-500">...</p>
) : plans.length === 0 ? ( ) : plans.length === 0 ? (