import { useState, useEffect, useCallback, useRef } from 'react'; import { api } from '../api.js'; import { isInspectionExpirySoon } from '../utils/carUtils.js'; import styles from './CarManagement.module.css'; export default function CarManagement({ reloadKey = 0 }) { const [cars, setCars] = useState([]); const [reservations, setReservations] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [newCarName, setNewCarName] = useState(''); const [newCarDesc, setNewCarDesc] = useState(''); const [newCarExpiry, setNewCarExpiry] = useState(''); const [newCarEtc, setNewCarEtc] = useState(false); const [newCarTire, setNewCarTire] = useState('ノーマル'); const [editingId, setEditingId] = useState(null); const [editName, setEditName] = useState(''); const [editDesc, setEditDesc] = useState(''); const [editExpiry, setEditExpiry] = useState(''); const [editEtc, setEditEtc] = useState(false); const [editTire, setEditTire] = useState('ノーマル'); const [submitting, setSubmitting] = useState(false); const [dragOverIdx, setDragOverIdx] = useState(null); const dragSrcIdx = useRef(null); const loadCars = useCallback(async () => { try { setLoading(true); const [carsData, resData] = await Promise.all([api.getCars(), api.getReservations()]); setCars(carsData); setReservations(resData); setError(null); } catch (e) { setError(e.message); } finally { setLoading(false); } }, []); useEffect(() => { loadCars(); }, [loadCars, reloadKey]); const handleAdd = async (e) => { e.preventDefault(); if (!newCarName.trim()) return; try { setSubmitting(true); await api.createCar({ name: newCarName.trim(), description: newCarDesc.trim(), inspection_expiry: newCarExpiry, has_etc: newCarEtc, tire_type: newCarTire, }); setNewCarName(''); setNewCarDesc(''); setNewCarExpiry(''); setNewCarEtc(false); setNewCarTire('ノーマル'); await loadCars(); } catch (e) { setError(e.message); } finally { setSubmitting(false); } }; const handleDelete = async (id, name) => { const carReservations = reservations.filter((r) => r.car_id === id); const message = carReservations.length > 0 ? `「${name}」を削除しますか?\n⚠ この代車には ${carReservations.length} 件の予約があります。削除するとこれらの予約もすべて削除されます。` : `「${name}」を削除しますか?\n関連する予約もすべて削除されます。`; if (!confirm(message)) return; try { await api.deleteCar(id); await loadCars(); } catch (e) { setError(e.message); } }; const startEdit = (car) => { setEditingId(car.id); setEditName(car.name); setEditDesc(car.description || ''); setEditExpiry(car.inspection_expiry || ''); setEditEtc(!!car.has_etc); setEditTire(car.tire_type || 'ノーマル'); }; const cancelEdit = () => { setEditingId(null); setEditName(''); setEditDesc(''); setEditExpiry(''); setEditEtc(false); setEditTire('ノーマル'); }; const handleUpdate = async (id) => { if (!editName.trim()) return; try { setSubmitting(true); await api.updateCar(id, { name: editName.trim(), description: editDesc.trim(), inspection_expiry: editExpiry, has_etc: editEtc, tire_type: editTire, }); cancelEdit(); await loadCars(); } catch (e) { setError(e.message); } finally { setSubmitting(false); } }; const applyReorder = async (newCars) => { setCars(newCars); try { await api.reorderCars(newCars.map((c) => c.id)); } catch (e) { setError(e.message); await loadCars(); } }; const handleReorder = async (index, direction) => { const swapIndex = index + direction; if (swapIndex < 0 || swapIndex >= cars.length) return; const newCars = [...cars]; [newCars[index], newCars[swapIndex]] = [newCars[swapIndex], newCars[index]]; await applyReorder(newCars); }; const handleDragStart = (index) => { dragSrcIdx.current = index; }; const handleDragOver = (e, index) => { e.preventDefault(); setDragOverIdx(index); }; const handleDragEnd = () => { setDragOverIdx(null); dragSrcIdx.current = null; }; const handleDrop = async (e, dropIndex) => { e.preventDefault(); const srcIndex = dragSrcIdx.current; setDragOverIdx(null); dragSrcIdx.current = null; if (srcIndex === null || srcIndex === dropIndex) return; const newCars = [...cars]; const [moved] = newCars.splice(srcIndex, 1); newCars.splice(dropIndex, 0, moved); await applyReorder(newCars); }; return (

代車管理

代車を追加

setNewCarName(e.target.value)} required /> setNewCarDesc(e.target.value)} />
{loading &&

読み込み中...

} {error &&

エラー: {error}

} {!loading && !error && (
{cars.length === 0 && ( )} {cars.map((car, carIdx) => ( handleDragStart(carIdx)} onDragOver={(e) => handleDragOver(e, carIdx)} onDragEnd={handleDragEnd} onDrop={(e) => handleDrop(e, carIdx)} className={dragOverIdx === carIdx ? styles.dragOver : ''} > {editingId === car.id ? ( <> ) : ( <> )} ))}
順番 車名 備考 車検満了日 ETC タイヤ 操作
代車がありません
setEditName(e.target.value)} /> setEditDesc(e.target.value)} /> setEditExpiry(e.target.value)} /> {car.name} {car.description || '-'} {car.inspection_expiry ? isInspectionExpirySoon(car.inspection_expiry) ? ⚠️ {car.inspection_expiry} : car.inspection_expiry : '-'} {car.has_etc ? ETC : 'なし'} {car.tire_type === 'スタッドレス' ? スタッドレス : 'ノーマル'}
)}
); }